与3317区别开,每个选手在面对当前局势最优能得到多少三角形是一样的,
即之前放的边是谁放的没关系,不会影响后面结果的统计
所以dp【state】表示在state下先手能得到最多多少个三角形
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<iomanip> #include <set> #include <cmath> #include <queue> #include <string> #include <vector> using namespace std; #define LINE 18 #define TRI 9 #define INF (1<<25) int edge[][2]={{1,2},{1,3},{2,3},{2,4},{2,5},{3,5},{3,6},{4,5},{5,6},{4,7},{4,8},{5,8},{5,9},{6,9},{6,10},{7,8},{8,9},{9,10}}; int tri[][3]= { {0,1,2}, {3,4,7},{2,4,5},{5,6,8}, {9,10,15},{7,10,11},{11,12,16},{8,12,13},{13,14,17} }; // 组成9个三角形的line编号,编号从0开始 int pw2[20],dp[(1<<18)+1000]; // 在这个状态下先手最多能得到多少个三角形 int cal(int state,int e) { int ret=0; for(int i=0;i<TRI;++i) { bool flag=false; for(int j=0;j<3;++j) if(e==tri[i][j]) flag=true; if(flag) { for(int j=0;j<3;++j) if(!(pw2[tri[i][j]]&state || e==tri[i][j])) { ret--;break; } ret++; } } return ret; } int dfs(int state) { if(dp[state]!=-INF) return dp[state]; int ret=-INF; for(int i=0;i<LINE;++i) if(!(state&pw2[i])) { int tt=cal(state,i); if(tt) tt+=dfs(state|pw2[i]); else tt-=dfs(state|pw2[i]); ret=max(ret,tt); } return dp[state]=ret; } int main () { pw2[0]=1; for(int i=1;i<=19;++i) pw2[i]=pw2[i-1]*2; for(int i=0;i<=(1<<18);++i) dp[i]=-INF; dp[(1<<18)-1]=0; // wa在这里了,好惨!!,所有边都填满的时候先手的那个人无法得到任何三角形,base case初始化 int test;scanf("%d",&test); for(int k=1;k<=test;++k) { int m,u,v;scanf("%d",&m); int side=0,m0=0,m1=0,state=0,tt; while(m--) { scanf("%d%d",&u,&v); // u<v for(int i=0;i<LINE;++i) if(edge[i][0]==u && edge[i][1]==v) { tt=cal(state,i); state=state|pw2[i]; side==0?m0+=tt:m1+=tt; side++; if(tt) side++; side%=2; break; } } int ans=m0-m1; if(side==0) ans+=dfs(state); else ans-=dfs(state); if(ans>0) printf("Game %d: A wins. \n",k); else printf("Game %d: B wins. \n",k); } return 0; }