传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4753
题意:给你一个4*4的格子16个点,两个人博弈,每次可以添加一条边,当添加一条边后围成1*1的正方形时就加一分,现在已经给你n个回合,问你到最后谁将得的分最高(两个人都是很聪明,每一步都是最优的)。
题解:因为12<=n<=24,所以剩下的边最多只有12条,用状态压缩即可(2^12)
dp[i]表示,S中放了边的状态为i的情况下,先走还能获得的最大分数。
每次dfs维护一个剩余的分数sum,表示当前状态下能获得的最大分数,dp[s]=max(sum-走一步后对手获得的最大分数)
注意一点他们两的得分之和为9,因为只有9个1*1的正方形。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <iterator>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <cctype>
using namespace std;
#define si1(a) scanf("%d",&a)
#define si2(a,b) scanf("%d%d",&a,&b)
#define sd1(a) scanf("%lf",&a)
#define sd2(a,b) scanf("%lf%lf",&a,&b)
#define ss1(s) scanf("%s",s)
#define pi1(a) printf("%d\n",a)
#define pi2(a,b) printf("%d %d\n",a,b)
#define mset(a,b) memset(a,b,sizeof(a))
#define forb(i,a,b) for(int i=a;i<b;i++)
#define ford(i,a,b) for(int i=a;i<=b;i++)
typedef __int64 LL;
const int N=22;
const int M=1000007;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-7;
struct node
{
int x,y;
}w;
int n;
int edge[N][N],dp[M],use[N];
vector<node> mp;
int fuck(int a,int b)
{
int sum=0;
if(a>b) swap(a,b);
if((b-a)==1) //横着的
{
if(a>=1&&a<=4)
{
int aa=a+4,bb=b+4;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
else if(a>=13&&a<=16)
{
int aa=a-4,bb=b-4;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
else
{
int aa=a+4,bb=b+4;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
aa=a-4,bb=b-4;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
}
else //竖着的
{
if(a%4==1)
{
int aa=a+1,bb=b+1;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
else if(a%4==0)
{
int aa=a-1,bb=b-1;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
else
{
int aa=a+1,bb=b+1;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
aa=a-1,bb=b-1;
if(edge[aa][a]&&edge[aa][bb]&&edge[bb][b])
sum++;
}
}
return sum;
}
int dfs(int now,int st,int last)
{
if(now>=25)//结束
return 0;
if(dp[st]!=-1)//记忆话搜索
return dp[st];
int ma=0;
for(int i=0;i<mp.size();i++)
{
if(use[i]) continue;
int x=mp[i].x,y=mp[i].y;
edge[x][y]=edge[y][x]=1;
use[i]=1;
ma=max(ma,last-dfs(now+1,st|(1<<i),last-fuck(x,y)));
use[i]=0;
edge[x][y]=edge[y][x]=0;
}
dp[st]=ma;
return ma;
}
int main()
{
// freopen("input.txt","r",stdin);
int T,ca=0;
si1(T);
while(T--)
{
int tom=0,jerry=0;
mset(edge,0);
si1(n);
ford(i,1,n)
{
int a,b;
si2(a,b);
edge[a][b]=edge[b][a]=1;
int k=fuck(a,b);
if(i&1) tom+=k;
else jerry+=k;
}
mp.clear();
ford(i,1,16) //统计剩下的边
ford(j,i+1,16)
{
if(edge[i][j]) continue;
if((j-i)==1&&i%4!=0){w.x=i;w.y=j;mp.push_back(w);}
if((j-i)==4){w.x=i;w.y=j;mp.push_back(w);}
}
mset(dp,-1);
mset(use,0);
if((n+1)<=24) //tom+jerry=9
{
if((n+1)&1)
{
tom+=dfs(n+1,0,9-tom-jerry);
jerry=9-tom;
}
else
{
jerry+=dfs(n+1,0,9-jerry-tom);
tom=9-jerry;
}
}
printf("Case #%d: %s\n",++ca,tom>jerry?"Tom200":"Jerry404");
}
return 0;
}
分享到:
相关推荐
hdu 1695 GCD(欧拉函数+容斥原理).docx
有题,有解题思路,有解题代码 hdu2516、poj1067和hdu1527、hdu2177、hdu2176等等
acm hdu as easy as a+b
ACM HDU 1404 Digital Deletions(博弈).docx
ACM题库,一些题目和答案,以及解题报告,传上来共享
很好很经典的组合博弈的讲义,HDU 大家下来看看很好
本人准备2020年保研机试时刷的题目(虽然最后机试取消了,...来自某中流985,在HDU和vjudge平台上大概刷了400道。本文件地图(excel表格)包含了绝大部分我刷过的题目,笔记中具有思路、代码、总结和心得。 大佬勿入!
杭电OnlineJudge 200-2099的解题报告
应同学之邀帮忙发布的一篇勘误 【HDU 3993】田忌赛马 题解+勘误 题解这里就略写一下了,主要是勘误。 这道题是2011年之前的多校...数据很小,可以考虑状态压缩+记忆化搜索 直接定义二维状态有很多浪费的空间,可以考虑u
hdu acm 教案 搜索入门 hdu acm 教案 搜索入门
HDU的1250,主要是利用高精度加法,但是代码有点繁琐,效率不是很高
300+ AC 代码 。 大数 , 线段树 , 字符串 , dp.....
杭电ACMhdu1163
HDU1059的代码
hdu1001解题报告
搜索 dfs 解题代码 hdu1241
hdu 1574 passed sorce
HDU的一题........HDU DP动态规
hdu 3341(ac自动机+状态压缩) 题意:容易理解... 思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A、T、C、G其中...
杭电组合博弈课件