选择我自己的算法 2012年CCC加拿大高中生信息学奥赛
Posted Koreyoshi.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了选择我自己的算法 2012年CCC加拿大高中生信息学奥赛相关的知识,希望对你有一定的参考价值。
在水城,你可能会看到一些鹅。你怎么在计算器上看到鹅呢?方法是输入35336,然后把计算器倒过来看,你就能看到gEESE——鹅了。
现在你的计算器的减号不给力了,只有+号和×号可以用,而且也只有部分数字可以工作。现在的任务是对于这个破烂的计算器能否通过简单的数字和固定数目的运算次数得到一个给定的目标值。
注意这个计算器的运算在被按下的时候就立即执行了,而不需要按照运算符优先级的规则。(见样例2)
输入描述
第一行输入一个整数W,表示你能够且必须使用的运算个数。W是是一个介于0到6之间的整数。结下来的一行是一个整数D(1 ≤ D ≤ 10),可以工作的数字键的个数。接下来的D行给出了这D个可以工作的数字键,这些数字键是0-9之间的互不重复的整数。然后给出一个整数V(1 ≤ V ≤ 5),即目标值的个数,接下来的V行每行一个介于0到5,000,000(包含)的整数,代表你需要用过计算器算出来的数值。
输出描述
输出包含V行,对应着V个目标值。每行是Y或者N,代表对应的目标值能在使用这D个数字并且刚好在W次运算的情况下被计算得到或者不能被计算得到。精确的说,一个目标值T能够计算得到的话,那是通过从D个数字钟的某个数字开始,通过加或乘其这些数字刚好W次,然后最后得到数值T。数字是可以重复使用的。数字也不需要全部被用完。但注意你不可以输入多位数。
样例输入1
6
3
6
7
8
1
35336
样例输入2
3
2
4
9
2
97
88
样例输出1:
Y
样例输出2:
N
Y
对于第二个数据,虽然4×4+9×9 = 97,但是由于计算的顺序是从左往右依次进行的,所以输出N。第二行,9+9+4*4就得到了88.
这道题目第一印象其实可以直接搜索
最多6个运算符7个数字,总状态共有2的6次方乘10的7次方
这个数远远大于计算机能共接受的1亿……
我们可以注意到任何一个答案,它一定由前一个数乘或加而得来
那么我们可以倒过来搜,如果目前得数可以被除或被加而得来,那么我们就进行除和减的递归,直到已经递归了W次(或者W加减1?次),看所得数是否可行。
这样我们的状态数大大被消减,饱和状态数大概是50000000*6左右,但是我们由于剪枝的存在根本不可能运行这么多次,估计算法完全可以保证状态数大大低于1000000(应该是……)
#include <iostream>
using namespace std;
int ANS,W;
int N;
int V;
bool q[100000000];
int temp;
bool can(int ans,int k)
{
if (k==0)
{
if (ans<=9)
{
if (q[ans])
return true;
else
return false;
}
else
return false;
}
for (int i=0;i<=9;i++)
if (q[i])
if (can(ans-i,k-1))
return true;
for (int i=1;i<=9;i++)
if (ans%i==0)
if (q[i])
if (can(ans/i,k-1))
return true;
if (ans==0)
if (can(0,k-1))
return true;
return false;
}
int main()
{
cin>>W;
cin>>N;
for (int i=1;i<=N;i++)
{
cin>>temp;
q[temp] = true;
}
cin>>V;
for (int i=1;i<=V;i++)
{
cin>>ANS;
if (can(ANS,W))
cout<<"Y"<<endl;
else
cout<<"N"<<endl;
}
return 0;
}
以上是关于选择我自己的算法 2012年CCC加拿大高中生信息学奥赛的主要内容,如果未能解决你的问题,请参考以下文章