CDOJ 1402 三角形棋盘上的博弈游戏 状压DP

来源:互联网 发布:免费oa办公系统源码 编辑:程序博客网 时间:2024/06/17 13:07

题目链接:这里

柱爷有天上课无聊,于是和同桌卿学姐一起下一种奇特的棋:

棋盘如图:

title

在开始游戏前,棋盘上已经放好了一些边,然后柱爷先手,开始在棋盘上没有边的位置添加一条边上去

如果添加边后围成一个三角形则获得一分(对于棋盘上游戏开始前已经围好了的三角形,两个人都不得分)并且下一轮还该他!否则下一轮该另一个人。

如果两个人都以最优策略下棋,那么柱爷能赢么?

注:只算最小的三角形!(三个边围成的三角形)

如果能赢输出“WIN!”

必败输出“LOSE!”

平局输出“Draw”

(都不输出引号)

愚人王感觉这规则太抽象了,都没人赶预测柱爷能不能赢了,于是画了个图解释了下题意:

title

对应: 5 1 2 3 4 5 的情况,如果这是开局情况,那么此时两个人都是0分,改柱爷先下,

如果他在6的位置填一条边,那么4,5,6将围城一个小三角形,柱爷得一分。接下来还是改柱爷下棋。

如果他在18的位置填一条边,那么将无法构成三角形,柱爷不得分,接下来改卿学姐下棋。

一直这样,直到填完所有边后,游戏结束。此时分高的人获胜,分相同则平局。
Input

第一行一个正整数n,表示开始游戏前有多少条边已经被放上去了。

第二行有n个正整数,a1…an代表已经放好的边的编号。

1<=a1…an<=18
Output
一行,输出柱爷的结局。
如果能赢输出“WIN!”
必败输出“LOSE!”
平局输出“Draw”

6
1 2 3 4 5 6
WIN!
5
4 5 6 7 8
LOSE!

//CDOJ 1402#include <bits/stdc++.h>using namespace std;int dp[1<<20][2]; //dp[i][0]表示i这个状态柱爷的最大得分,dp[i][1]表示i这个状态卿学姐的最大得分int viss[1<<20][2];int vis[30];int cal(int x){//计算状态x没构成三角形的虚线三角形的个数    memset(vis, 0, sizeof(vis));    for(int i = 1; i <= 18; i++)        if((x>>i)&1) vis[i] = 1;    int ans = 0;    for(int i = 0; i < 6; i++){        if(vis[3*i+1]&&vis[3*i+2]&&vis[3*i+3]) ans++;    }    if(vis[3]&&vis[5]&&vis[7]) ans++;    if(vis[6]&&vis[11]&&vis[13]) ans++;    if(vis[9]&&vis[14]&&vis[16]) ans++;    return 9-ans;}int dfs(int now, int flag){    if(viss[now][flag]) return dp[now][flag];    viss[now][flag] = 1;    int last = cal(now);    for(int i = 1; i <= 18; i++){        if(((now>>i)&1)==0){            int nxt = now|(1<<i);            int num = last - cal(nxt);            if(num > 0){//柱爷可以继续                dp[now][flag] = max(dp[now][flag], dfs(nxt, flag)+num);            }            else{//换卿学姐                dp[now][flag] = max(dp[now][flag], last - dfs(nxt, 1-flag));            }        }    }    return dp[now][flag];}int main(){    int n, now = 0;    scanf("%d", &n);    while(n--){        int x; scanf("%d", &x); now |= (1<<x);    }    int last = cal(now);    int a = dfs(now, 0);    int b = last - a;    if(a > b) puts("WIN!");    else if(a < b) puts("LOSE!");    else puts("Draw");    return 0;}
0 0