题意:在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;
}