poj1143 DP+dfs+位运算- -

DP+dfs+位运算- -

脑袋都大了- -

因为一个位运算忘记写  ‘=’ 了 ,用了好久才找到错误!!!!!

题目大意:Christine和Matt玩一个游戏.游戏的规则如下:一开始有一列数字(2~20),有的被列出,有的没有列出.从Christine开始,两人轮流划去一个已被列出的数字.每划去一个数字,其他的所有的能被不在这个数列的数字的两两整线性表示的数也自动从数列中退出.到最后,轮到某人而此时数列中没有元素时,这个人就输了.
规定:winning move能将对手置于losing position的决策;而losing position不存在任何winning move的序列.

解题大体思路,定义输入N(N<=20)个数字为一个状态,扫描这些输入的数字,假设选择数字num(扫描到num)后,如果当前状态有数字可选 并且 选择num后搜索剩下的数字组成的状态为没有数字可选,则选择的数字num为winning move.

N(N<=20)个数字组成的状态,想办法寻找能对应这个状态的hash函数,于是可以有一个20位的数(unsigned int 的低20位)表示,这位为1表示这位在输入数字中,为0表示不在输入数字中。则可定义一个数组record表示状态(有数字可选、没有数字可选、不确定),数组大小为(1<<20),数组的每一个下标是一个状态(表示一组输入),下标对应的值为状态。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <fstream>
#include <math.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn =21;
int record[1 << maxn];
int n;
int mapstate(bool *s)
{
	int index=0;
	for(int i=2;i<maxn;i++)
	{
		if(s[i])
			index |= 1;
		index <<= 1;
	}
	return (index >> 1);
}
bool dfs(bool *s,int x)  //true可以赢,false不能赢
{
	bool cur[maxn];
	memcpy(cur,s,maxn);
	cur[x]=false;//把目前编号 标记用过
	for(int i=2;i+x<21;i++)
	{
		if(!cur[i])  
			cur[i+x]=false;//标记  用过编号+目前编号
	}
	int index =mapstate(cur);
	if(record[index]>0)
		return true;
	else if(record[index]<0)
		return false;

	for(int i=2;i<maxn;i++)//对方选i
	{
		if(cur[i]&&!dfs(cur,i)) //对方能选,且对方能赢
		{
			record[index]=1;//标记这个状态不可行
			return true;//返回不可行
		}
	}
	record[index]=-1;//否则该状态可行
	return false;

}
int main()
{ifstream cin("input.txt");
	bool vis[maxn];
	int kase=1;
	while(cin>>n,n)
	{
		memset(vis,0,sizeof(vis));
		
		for(int i=0;i<n;i++)
		{int x;
			cin>>x;
			vis[x]=true;
		}
		int index=mapstate(vis);
		//memset(record,0,sizeof(record));
		int ans[maxn];
		int a=0;
		for(int i=2;i<maxn;i++)
		{
			if(vis[i]&&!dfs(vis,i))//遍历所有值,如果这个数可以选,并且选了能赢
			{
				ans[a++]=i;//记录下来,一会输出
			}
		}
		printf("Test Case #%d\n",kase++);
		if(a==0) {
			record[index]=-1;
			printf("There's no winning move.\n");
		}
		else {
			printf("The winning moves are:");
			for(int i=0;i<a;i++)
				printf(" %d",ans[i] );
			cout<<endl;
		}
		cout<<endl;
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值