POJ 1085 博弈-搜索

5 篇文章 0 订阅

与3317区别开,每个选手在面对当前局势最优能得到多少三角形是一样的,

即之前放的边是谁放的没关系,不会影响后面结果的统计

所以dp【state】表示在state下先手能得到最多多少个三角形


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include <set>
#include <cmath>
#include <queue>
#include <string>
#include <vector>
using namespace std;
#define LINE 18
#define TRI 9
#define INF (1<<25)
int edge[][2]={{1,2},{1,3},{2,3},{2,4},{2,5},{3,5},{3,6},{4,5},{5,6},{4,7},{4,8},{5,8},{5,9},{6,9},{6,10},{7,8},{8,9},{9,10}};
int tri[][3]=
{
	{0,1,2},
	{3,4,7},{2,4,5},{5,6,8},
	{9,10,15},{7,10,11},{11,12,16},{8,12,13},{13,14,17}
}; // 组成9个三角形的line编号,编号从0开始
int pw2[20],dp[(1<<18)+1000]; // 在这个状态下先手最多能得到多少个三角形
int cal(int state,int e)
{
	int ret=0;
	for(int i=0;i<TRI;++i)
	{
		bool flag=false;
		for(int j=0;j<3;++j)
			if(e==tri[i][j])
				flag=true;
		if(flag)
		{
			for(int j=0;j<3;++j)
				if(!(pw2[tri[i][j]]&state || e==tri[i][j]))
				{
					ret--;break;
				}
			ret++;
		}
	}
	return ret;
}

int dfs(int state)
{
	if(dp[state]!=-INF) 
		return dp[state];
	int ret=-INF;
	for(int i=0;i<LINE;++i)
		if(!(state&pw2[i]))
		{
			int tt=cal(state,i);
			if(tt)
				tt+=dfs(state|pw2[i]);
			else tt-=dfs(state|pw2[i]);
			ret=max(ret,tt);
		}
	return dp[state]=ret;
}
int main ()
{
	pw2[0]=1;
	for(int i=1;i<=19;++i)
		pw2[i]=pw2[i-1]*2;
	for(int i=0;i<=(1<<18);++i)
		dp[i]=-INF;
	dp[(1<<18)-1]=0; // wa在这里了,好惨!!,所有边都填满的时候先手的那个人无法得到任何三角形,base case初始化
	int test;scanf("%d",&test);
	for(int k=1;k<=test;++k)
	{
		int m,u,v;scanf("%d",&m);
		int side=0,m0=0,m1=0,state=0,tt;
		while(m--)
		{
			scanf("%d%d",&u,&v); // u<v
			for(int i=0;i<LINE;++i)
				if(edge[i][0]==u && edge[i][1]==v)
				{
					tt=cal(state,i);
					state=state|pw2[i];
					side==0?m0+=tt:m1+=tt;
					side++;
					if(tt)
						side++;
					side%=2;
					break;
				}
		}
		int ans=m0-m1;
		if(side==0)
			ans+=dfs(state);
		else ans-=dfs(state);
		if(ans>0)
			printf("Game %d: A wins. \n",k);
		else printf("Game %d: B wins. \n",k);
	}
	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值