您的位置:首页 > 其它

ZOJ1039

2016-01-25 11:10 295 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=39

记忆化搜索。这个题也相当郁闷,开始用f[i][j]表示第 i 次选择时 j 是不是必胜数,如果选择 j 后没有必胜数,那么 j 就是必胜数,反之不是必胜数,用DFS(i, j)来判断,总是不对,郁闷死了。后来看题解,用二进制状态压缩,于是改成二进制状态压缩,搜索的方式也改成和题解一样的,只是对于除去非法数字的方法不同,但仍然是错,恶心。

#include<iostream>
#include<cstring>

using namespace std;

int f[1<<21];
bool g[1<<21];
bool used[25];

void Chenge(int i)
{
int j = i;

while (j <= 20)
{
used[j] = true;
//for (int k=2; k<=20; k++)
//    if (used[k] && k+j <=20)
//        used[k+j] = true;
j += i;
}
}

void Back(bool tmp[])
{
for (int i=0; i<25; i++)
used[i] = tmp[i];
}

int work()
{
int now = 0;

for (int i=1; i<=20; i++)
if (!used[i])
now += 1<<i;
return now;
}

int DFS()
{
int now = work();
if (g[now])
return f[now];

g[now] = true;
f[now] = 0;
bool tmp[25];
for (int i=0; i<25; i++) tmp[i] = used[i];

for (int i=2; i<=20; i++)
if (!used[i])
{
Chenge(i);
int New = work();
int x = DFS();
if (x == 0)
f[now] += (1<<(i-1)) ;
Back(tmp);
}
return f[now];
}

int main()
{
int t;
int k = 0;

cin>>t;
while (t--)
{
k++;
memset(used,true,sizeof(used));
memset(f,false,sizeof(f));
memset(g,false,sizeof(g));
int a;
cin>>a;
for (int i=0; i<a; i++)
{
int x;
cin>>x;
used[x] = false;
}

int ans = 0;
cout<<"Scenario #"<<k<<":"<<endl;
if (!(ans = DFS()))
{
cout<<"There is no winning move."<<endl;
continue;
}
cout<<"The winning moves are:";
for (int i=1; i<=20; i++)
{
if (ans % 2 == 1)
cout<<' '<<i;
ans >>= 1;
if (ans == 0)
break;
}
cout<<"."<<endl;
cout<<endl;
}
}


后来还是看题解。用二进制表示,从低位到高位,分别表示1到20是否在集合中。要判断一个数 j 是不是在集合中,只要&一下2^j就就可以了,结果位1,则在集合中,否则不在集合中。只是对于除去非法数字的方法没有看懂,郁闷。

#include<iostream>
#include<cstring>

using namespace std;

int f[1<<21];
int mask[1<<21];

int DFS(int num)
{
if (f[num] == -1)
{
f[num] = 0;
for (int i=2; i<=20; i++)
if ((num & mask[i]) != 0)
{
int tmp = num;
int j = i;
while (j<=20)
{
int buf = (((num | 1) << j) | (mask[j]-1));
tmp &= buf;
j += i;
}
int x = DFS(tmp);
if (x == 0)
f[num] += mask[i];
}
}
return f[num];
}

int main()
{
int t;
int k = 0;

cin>>t;
while (t--)
{
k++;
memset(f,255,sizeof(f));
for (int i=1; i<=20; i++)
mask[i+1] = 1<<i;

int a = 0,n;
cin>>n;
for (int i=0; i<n; i++)
{
int x;
cin>>x;
a |= mask[x];
}

int ans = DFS(a);
cout<<"Scenario #"<<k<<":"<<endl;
if (ans == 0)
{
cout<<"There is no winning move."<<endl;
cout<<endl;
continue;
}
cout<<"The winning moves are:";
for (int i=1; i<=20; i++)
{
if (ans % 2 == 1)
cout<<' '<<i;
ans >>= 1;
if (ans == 0)
break;
}
cout<<"."<<endl;
cout<<endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: