题意:在3*3的方格中,有4*4=16个点,标号分别为1~16,A、B两人轮流玩游戏,每次可以添加一条边(相邻节点),如果恰好能够凑成一个边长为1的正方形则得一分,两个的话得2分。现在给定两人已经连接的n条边后,求最终格局谁会胜。
因为总计只有24条边,而且只能剩下0--12条边,所以状态压缩记录好剩下还没走好的步数,dp[i]表示状态i下,当前玩家能获得的最大分数。
如何处理连边,方法多多,随意YY..............本人用vis[a][b] 表示,为0表示a,b无边,为1表示有边但是游戏进行到当前此边未使用,为2表示有边并且此边已经使用..................
#include <iostream> #include <algorithm> #include <cmath> #include<functional> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <climits>//形如INT_MAX一类的 #define MAX 100005 #define INF 0x7FFFFFFF #define REP(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define L(x) x<<1 #define R(x) x<<1|1 # define eps 1e-5 using namespace std; int n,sumA,sumB; int dp[5555],used[30]; int vis[30][30]; struct node { int a,b; } ed[30]; int num; void init() { sumA = 0; sumB = 0; num = 0; memset(used,0,sizeof(used)); memset(dp,-1,sizeof(dp)); memset(vis,0,sizeof(vis)); for(int i=0; i<=3; i++) { for(int j=1; j<=3; j ++) { int a = i * 4 + j; int b = i * 4 + j + 1; vis[a][b] = 1; vis[b][a] = 1; } } for(int i=1; i<=12; i++) { int a = i; int b = i + 4; vis[a][b] = 1; vis[b][a] = 1; } } int cal() { //计算到目前已经得到的分数 int cnt = 0; for(int i=0; i<3; i++) { for(int j=1; j<=3; j++) { int a = i * 4 + j; int b = a + 1; int c = a + 4; int d = c + 1; if(vis[a][b] == 2 && vis[a][c] == 2 && vis[c][d] == 2 && vis[b][d] == 2 ) cnt ++; } } return cnt ; } int dfs(int step,int cur) { if(step == 25 || cur == 0) return 0; int buff = 0; for(int i=0; i<num; i++) { if(used[i] == 1) buff = buff | (1 << i); } if(dp[buff] != -1) return dp[buff]; int cmp = 0; for(int i=0; i<num; i++) { if(used[i] == 1) continue; used[i] = 1; vis[ed[i].a][ed[i].b] = 2; vis[ed[i].b][ed[i].a] = 2; int t = cal(); cmp = max(cmp,cur - dfs(step + 1,9 - t)); used[i] = 0; vis[ed[i].a][ed[i].b] = 1; vis[ed[i].b][ed[i].a] = 1; } return dp[buff] = cmp; } int main() { int T; cin >> T; int ca = 1; while(T--) { init(); scanf("%d",&n); int cnt = 0,a,b; for(int i=1; i<=n; i++) { scanf("%d%d",&a,&b); vis[a][b] = 2; vis[b][a] = 2; int t = cal(); if(i % 2 == 1) sumA += t - cnt; else sumB += t - cnt; cnt = t; } printf("Case #%d: ",ca++); if(sumA >= 5) { printf("Tom200\n"); continue; } if(sumB >= 5) { printf("Jerry404\n"); continue; } //把剩余的边统计出来 for(int i=1; i<=15; i++) { for(int j=i+1; j<=16; j++) { if(vis[i][j] == 1) { ed[num].a = i; ed[num].b = j; num++; } } } int cur = 9 - sumA - sumB; if((n+1) % 2 == 1) { sumA += dfs(n+1,cur); sumB = 9 - sumA; } else { sumB += dfs(n+1,cur); sumA = 9 - sumB; } //cout << sumA << ' ' << sumB << endl; if(sumA > sumB) printf("Tom200\n"); else printf("Jerry404\n"); } return 0; }