CF786A - Berzerk

  1 /*
  2  CF786A - Berzerk
  3  http://codeforces.com/contest/786/problem/A
  4  博弈论
  5  直接搜出NP状态图。记得要记忆化剪枝。
  6  *
  7  */
  8 #include <cstdio>
  9 #include <cstring>
 10 //#define tle
 11 #ifdef tle
 12 //#define test
 13 
 14 using namespace std;
 15 const int Nmax=7005;
 16 int now;
 17 int is[2][Nmax];
 18 int n;
 19 int s[2][Nmax];
 20 int tmp[2][Nmax];
 21 int k[2];
 22 #ifdef test
 23 void watch()
 24 {
 25     for(int i=0;i<=1;i++)
 26     {
 27         printf("s[%d]:\n",i);
 28         for(int j=1;j<=n;j++)
 29             printf("%d ",is[i][j]);
 30         printf("\n");
 31     }
 32 }
 33 #endif
 34 
 35 void work()
 36 {
 37     for(int j=0;j<=1;j++)
 38     for(int i=1;i<=k[j];i++)
 39     {
 40         int x=(n+1-s[j][i])%n;
 41         while(x<=0)
 42             x+=n;
 43         is[j][x]=1;
 44     }
 45     #ifdef test
 46     watch();
 47     #endif
 48 
 49     for(int t=1;t<=100000;t++)
 50     {
 51         for(int ii=0;ii<=1;ii++)
 52             for(int jj=1;jj<=n;jj++)
 53                 tmp[ii][jj]=is[ii][jj];
 54     for(int now=0;now<=1;now++)
 55     for(int i=2;i<=n;i++)
 56     {
 57         if(is[now][i]!=-1)
 58             continue;
 59         int flag=0;
 60         for(int j=1;j<=k[now];j++)
 61         {
 62             int x=(i+s[now][j])%n;
 63             while(x<=0)
 64                 x+=n;
 65             if(is[now^1][x]==0)
 66             {
 67                 is[now][i]=1;
 68                 flag=1;
 69                 break;
 70             }
 71             if(is[now^1][x]==-1)
 72                 flag=1;//标记不是P态
 73         }
 74         if(!flag)
 75             is[now][i]=0;    
 76 #ifdef test
 77         printf("is[%d][%d]:\n",now,i);
 78     watch();
 79     #endif
 80     
 81     }
 82     int ff=0;
 83     for(int ii=0;ii<=1;ii++)
 84     {
 85         if(ff)
 86             break;
 87         for(int jj=1;jj<=n;jj++)
 88             if(tmp[ii][jj]!=is[ii][jj])
 89             {
 90                 ff=1;
 91                 break;
 92             }
 93     }
 94     if(!ff)
 95         break;
 96     }
 97 
 98 }
 99 
100 void init()
101 {
102     for(int i=1;i<=n;i++)
103         is[0][i]=is[1][i]=-1;
104     is[0][1]=is[1][1]=1;
105 }
106 int main()
107 {
108     scanf("%d",&n);
109     for(int i=0;i<=1;i++)
110     {
111         scanf("%d",&k[i]);
112         for(int j=1;j<=k[i];j++)
113             scanf("%d",&s[i][j]);
114     }
115     init();
116     work();
117     for(int t=0;t<=1;t++)
118     {
119         for(int i=2;i<=n;i++)
120         {
121             if(i!=2)
122                 printf(" ");
123             if(is[t][i]==-1)
124                 printf("Loop");
125             else if(is[t][i]==0)
126                 printf("Lose");
127             else
128                 printf("Win");
129         }
130         printf("\n");
131     }
132 }
133 #endif
134 
135 using namespace std;
136 const int Nmax=7005;
137 int now;
138 int is[2][Nmax];
139 int n;
140 int s[2][Nmax];
141 int tmp[2][Nmax];
142 int k[2];
143 
144 void dfs(int now,int x,int sstatus)
145 {
146     if(is[now][x]!=-1)//如果已经有状态了,返回
147         return;
148     is[now][x]=sstatus;
149     if(sstatus==0)//如果当前点为必败态,则让与其相接的点为必胜态
150     {
151         for(int i=1;i<=k[now^1];i++)
152         {
153             int next=(x-s[now^1][i])%n;
154             while(next<=0)
155                 next+=n;
156             dfs(now^1,next,1);
157         }
158     }
159     if(sstatus==1)//如果当前点为必胜态,则让与其相接的点的非必胜态边个数-1
160     {
161         for(int i=1;i<=k[now^1];i++)
162         {
163             int next=(x-s[now^1][i])%n;
164             while(next<=0)
165                 next+=n;
166             tmp[now^1][next]--;//利用tmp数组记录当前相接的点的非必胜态个数来剪枝,如果相邻点都是必胜态,则当前点为必败态
167             if(!tmp[now^1][next])
168                 dfs(now^1,next,0);
169         }
170     }
171 }
172 
173 void init()
174 {
175     for(int i=1;i<=n;i++)
176         is[0][i]=is[1][i]=-1;
177     is[0][1]=is[1][1]=0;
178 }
179 int main()
180 {
181     scanf("%d",&n);
182     for(int i=0;i<=1;i++)
183     {
184         scanf("%d",&k[i]);
185         for(int j=1;j<=k[i];j++)
186             scanf("%d",&s[i][j]);
187         for(int j=1;j<=n;j++)
188             tmp[i][j]=k[i];
189     }
190     init();
191     for(int j=0;j<=1;j++)
192     for(int i=1;i<=k[j];i++)
193     {
194         int x=(n+1-s[j][i])%n;
195         while(x<=0)
196             x+=n;
197         dfs(j,x,1);
198     }
199     for(int t=0;t<=1;t++)
200     {
201         for(int i=2;i<=n;i++)
202         {
203             if(i!=2)
204                 printf(" ");
205             if(is[t][i]==-1)
206                 printf("Loop");
207             else if(is[t][i]==0)
208                 printf("Lose");
209             else
210                 printf("Win");
211         }
212         printf("\n");
213     }
214     return 0;
215 }

 

转载于:https://www.cnblogs.com/BBBob/p/6612753.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值