HDU 4753 Fishhead’s Little Game (对抗搜索)

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


你可能感兴趣的:(HDU 4753 Fishhead’s Little Game (对抗搜索))