十三分之五是反革命,咱们的输出要求付出四个整形的数字

Flip Game
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 37427   Accepted: 16288

Description

Flip game is played on a rectangular 4×4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it’s black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules: 

  1. Choose any one of the 16 pieces. 
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

Consider the following position as an example: 

bwbw 
wwww 
bbwb 
bwwb 
Here "b" denotes pieces lying their black side up and "w" denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become: 

bwbw 
bwww 
wwwb 
wwwb 
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal. 

Input

The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position.

Output

Write to the output file a single integer number – the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it’s impossible to achieve the goal, then write the word "Impossible" (without quotes).

Sample Input

bwwb
bbwb
bwwb
bwww

Sample Output

4

Source

图片 1

Description

小A和小B又想开了三个新的游乐。

以此娱乐是在多个一*n的棋盘上海展览中心开的,棋盘上有k个棋子,五分之3是土红,5/10是反动。

最左侧是反动棋子,最右侧是海蓝棋子,相邻的棋类颜色各异。

小A能够活动草地绿棋子,小B能够活动深紫的棋子,他们每一次操作能够移动1到d个棋子。

每当移动某3个棋卯时,那个棋子不能够当先两边的棋子,当然也不得以出界。当什么人不得以操作时,何人就破产了。

小A和小B轮流操作,未来小A先活动,有个别许种开端棋子的布局会使她胜利呢?

 

 

Input

共一行,三个数,n,k,d。

难题疏忽

在历史上,关于黑白棋(官方名叫奥赛罗),有过五个变种,比如这一弹中,笔者准备付出个中壹种(和本身在Round
七中介绍的熄灯难点)比较相似的(甚至足以说是大概一摸一样)的娱乐,其名字叫做翻转棋(Flip
Game)。那款游戏的规则非凡简单,在3个4*4的界面中,随意翻转3个子,其自小编以及相近的棋子都会随着翻转并转换其颜色。理解了平整之后,我们能够付出如下的AI,该AI能够反过来最短的次数,来找到对象地方(能够是全黑(All
Black)也许是全白(All
惠特e))。在“熄灯难点”中,大家说过1种艺术叫做BFS+Enum(也正是广度优先搜索同盟枚举),那里注意的有个别是,我们不可能利用STL里面的容器(包括bitset和queue),因为会时有爆发溢出。那里,大家将数组改变成队列或许栈,在655三十三个长度以内都不会发生溢出的题材了。

Output

出口小A胜利的方案总数。答案对1000000007取模。

  有$4\times
四$的棋盘,上面包车型大巴棋类一面是黑的,一面是白的。规定翻转三个棋子的还要也要扭转它的上、下、左、右的棋子,问给定一个棋盘的棋子状态,至少供给扭转多少个棋子,能使得全数棋子都是白的或黑的(面在上)。

 

Sample Input

10 4 2

基本思路

Problem——源自POJ
17伍三,给出4行四列的十两个字符,b代表黑子(black),w代表白子(white),大家的出口须要提交一个整形的数字,来表示最少三回就能够达成大家所急需的靶子。假诺完全不可能达到规定的标准的话,就输出Impossible。

Sample Output

182

1、暴力搜索出奇迹:

队列完结:

HINT

 1<=d<=k<=n<=10000, k为偶数,k<=100。

 

正解:博弈论+$dp$。

推荐博客:$nim$游戏及其变形

首先标题仿佛漏了一句话,正是白棋不能够右移,黑棋无法左移。。

因为每对黑白棋相邻,所以其实大家得以转化一下模型,每对黑白棋正是一堆石子,它们的偏离$-一$便是石子个数。

明日每一趟能够取$d$个石子堆中的石子,问先手必胜的方案有多少?

那是3个经典的$nim-k$难题,结论是对此石子堆的每八个贰进制位,即便那1个人上为$1$的石子堆数是$d+一$的翻番,那么先手必败。

从而大家得以一贯思量先手必败的方案数,再用总方案数减去即可。

设$f[i][j]$表示思量到贰进制从小到大的第$i$位,当前石子总数为$j$,先手必败的方案数。

那么$f[i+1][j+p*(d+1)*2^{i}]+=f[i][j]*\binom{k/2}{p*(d+1)}$,注意第2维必须$\leq
n-k$。

最后我们枚举石子数$i$,那么$Ans-=f[15][i]*\binom{n-k/二-i}{k/二}$,那里能够看成在法定地点中采纳$k/二$个职位的方案数。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (1000000007)
 6 
 7 using namespace std;
 8 
 9 int c[10005][105],f[16][10005],n,k,d,ans;
10 
11 il int gi(){
12   RG int x=0,q=1; RG char ch=getchar();
13   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
14   if (ch=='-') q=-1,ch=getchar();
15   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
16   return q*x;
17 }
18 
19 il int C(RG int n,RG int m){
20   return n<m ? 0 : c[n][min(m,n-m)];
21 }
22 
23 int main(){
24 #ifndef ONLINE_JUDGE
25   freopen("chess.in","r",stdin);
26   freopen("chess.out","w",stdout);
27 #endif
28   n=gi(),k=gi(),d=gi(),c[0][0]=1;
29   for (RG int i=1;i<=n;++i){
30     c[i][0]=1;
31     for (RG int j=1;j<=k && j<=i;++j){
32       c[i][j]=c[i-1][j-1]+c[i-1][j];
33       if (c[i][j]>=rhl) c[i][j]-=rhl;
34     }
35   }
36   f[0][0]=1,ans=C(n,k);
37   for (RG int i=0;i<15;++i)
38     for (RG int j=0;j<=n-k;++j)
39       for (RG int p=0,q;p*(d+1)<=(k>>1);++p){
40     q=j+p*(d+1)*(1<<i); if (q>n-k) break;
41     f[i+1][q]=(1LL*f[i][j]*C(k/2,p*(d+1))+f[i+1][q])%rhl;
42       }
43   for (RG int i=0;i<=n-k;++i){
44     ans=(-1LL*f[15][i]*C(n-k/2-i,k/2)+ans)%rhl;
45     if (ans<0) ans+=rhl;
46   }
47   cout<<ans; return 0;
48 }

 

  1、首先要明白一点:这些翻棋子就像是按位异或平等,假如1列数里面有四个数是分外的,那把它们全都异或起来,依照结合率就一定于在那进度中有贰个数与本身异或,结果为0。把那五个十二分的数去掉对最终异或结果是不曾影响的。同样看那一个翻棋子,它唯有四个面,翻叁回由黑面在上转为白面在上,大概白转黑,但翻四次就复苏原先的样板了,翻没翻是如出1辙的,除非再翻多一回,甚至是奇多次,但那从没供给也未有意思。

  1 /*
  2 
  3     Highlights:
  4 
  五    (一)为了博取更多的装填量,利用数组模拟队列,而不使用STL中的各个容器
  6 
  七    (二)一<<x表示置x位为黑位,十九个格子,正好用short int的短整型数表示十六个点
  8 
  九    (三)巧妙运用XO昂科拉运算,将每一遍变动后的情形存款和储蓄
 10 
 11  */
 12 
 13  
 14 
 15  #include<iostream>
 16 
 17  #include<queue>
 18 
 19  using namespace std;
 20 
 21  
 22 
 23  int step[65535]; //利用数组,能够博得比容器更多的装载量(那里表示拥有相当大恐怕的装载量)
 24 
 25  bool flag[65535]; //制止重复搜索
 26 
 27  unsigned short qState[65535]; //搜索的景观,由于65536=2^1陆,所以能够用每一位的’0’和’一’状态标记是或不是被寻找
 28 
 29  
 30 
 3一  int rear=0; //队列尾指针
 32 
 3三  int top=0; //队列头指针
 34 
 35  
 36 
 ③⑦  //发轫化,读入棋盘的始发状态并将其转化为13位数存款和储蓄在头队列中
 38 
 39  //黑为’1’而白为’0′
 40 
 41  
 42 
 43  void init()
 44 
 45  {
 46 
 47    unsigned short temp=0;//无字符短整型变量,省空间
 48 
 4玖    char c;//每趟读入一个字符
 50 
 51    for(int i=0;i<4;i++)
 52 
 53    {
 54 
 55      for(int j=0;j<4;j++)
 56 
 57      {
 58 
 59        cin>>c;
 60 
 6一        if(‘b’==c)//注意那样写的妙处!要是写成c==’b’很简单和c=’b’混淆
 62 
 63          temp=temp|(1<<(i*肆+j));//将黑地方为高位       
 64 
 65      }       
 66 
 67    }    
 68 
 69    qState[rear++]=temp;//载入状态队列
 70 
 71    flag[temp]=true;//标记该位
 72 
 73  }
 74 
 75  
 76 
 7七  //翻转3个棋子,并依据规则对周边棋子施加影响
 78 
 79  unsigned short move(unsigned short state,int i)
 80 
 81  {
 82 
 83    unsigned short temp=0;
 84 
 85    temp|=(1<<i);
 86 
 87    if((i+1)%4!=0) //不在最右的右
 88 
 89      temp|=(1<<(i+1));
 90 
 91    if(i%4!=0) //不在最左的左
 92 
 93      temp|=(1<<(i-1));
 94 
 95    if(i+4<16) //下
 96 
 97      temp|=(1<<(i+4));
 98 
 99    if(i-4>=0) //上
100 
101      temp|=(1<<(i-4));
102 
103    return (state^temp);//XOLacrosse异或运算        
104 
105  }
106 
107  
108 
10⑨  //接纳BFS将每一遍
110 
111  bool BFS()
112 
113  {
114 
11伍    while(rear>top)//直到行列中无成分
116 
117    {
118 
11玖      //那一个命令是在模仿qState.pop();
120 
121      unsigned short state=qState[top++];
122 
123      for(int i=0;i<16;i++)
124 
125      {
126 
127        unsigned short temp;
128 
129        temp=move(state,i);       
130 
131        if(0==state||6553伍==state)//上述说过的技艺
132 
133        {
134 
135          cout<<step[state]; 
136 
137          return true;                        
138 
139        }
140 
141        else if(!flag[temp])//幸免重复搜索
142 
143        {
144 
145          //模拟进队列操作qState.push(temp);
146 
147          qState[rear++]=temp;
148 
149          flag[temp]=true;
150 
151          step[temp]=step[state]+1;    
152 
153        }
154 
155      }              
156 
157    }    
158 
159    return 0;
160 
161  }
162 
163  
164 
165  int main()
166 
167  {
168 
169    init();
170 
171    if(!BFS()) cout<<“Impossible”;
172 
173    char c;
174 
175    cin>>c;
176 
177    return 0;   
178 
179  }

  二、数据规模小,思虑大家起码不翻任何棋子(初始状态就是全白或全黑),最八只翻17个棋子(再翻就有棋子被翻五回了),因而总的状态数为$C^{0}_{16}+C^{1}_{16}+\cdots+C^{16}_{1陆}=2^{1陆}$,直接枚举或探寻即可。

  3、思考必要的是十分的小值,由此从翻$0$个初叶,搜索翻$i$个,直到翻$16$个,中间搜索到即为最小值,翻十四个都不知足即出口$Impossible$。

  四、由于棋子都只有黑、白两面,能够用0、一象征,因此得以位压缩成一个数字来展开判断,翻棋子的操作可接纳位运算,有三种办法:

    方法一:每壹行压缩二个数字,对第$i$行第$j$列棋子举办翻转,比如$j=二$,则$i-壹$、$i+一$行的棋子应该和四(0拾0)相异或(与1异或切换状态,与0异或不转移),而第$i$行棋子应与1四(11十)相异或。

    方法2:唯有17个棋子,一个int型变量就能存下那15个0/一了,所以能够一直压缩成贰个数字。如$i=2,
j=贰$,则与20042(0拾0 11拾 0100
0000)相异或,但是手算拾伍位的气象是比手算3位烦一丝丝。

  5、搜索进程中要专注搜过的岗位不需求再搜了,所以在函数里决定一下$i$、$j$,当然达成并不唯1。还要注意假如没搜成功,把棋子再翻(flip)一次,那样就能上升原样了。不须要memcpy,那是很蠢的做法。

格局一代码:

图片 2图片 3

 1 #include <stdio.h>
 2 
 3 int field[6]={0};
 4 int state[][4]={{8,4,2,1},{12,14,7,3}};
 5 
 6 void read() {
 7     for(int i=1; i<=4; i++) {
 8         for(int j=1; j<=4; j++) {
 9             field[i]<<=1;
10             if(getchar()=='b')
11                 field[i]|=1;
12         }
13         getchar();
14     }
15 }
16 
17 void flip(int i, int j) {--j;
18     field[i-1]^=state[0][j];
19     field[i]  ^=state[1][j];
20     field[i+1]^=state[0][j];
21 }
22 
23 bool check() {
24     return (field[1]==0||field[1]==15)
25          && field[1]==field[2]
26          && field[2]==field[3]
27          && field[3]==field[4];
28 }
29 
30 bool find(int n, int i, int j) {
31     if(n==0) return check();
32     j+=1; if(j>4) i+=1, j=1;
33     if(i>4) return false;
34     for(; i<=4; i++) {
35         for(; j<=4; j++) {
36             flip(i, j);
37             if(find(n-1,i,j))
38                 return true;
39             flip(i, j);
40         }
41         j=1;
42     }
43     return false;
44 }
45 
46 void work() {
47     for(int i=0; i<=16; i++)
48         if(find(i,1,0)) {
49             printf("%d\n", i);
50             return;
51         }
52     puts("Impossible");
53 }
54 
55 int main() {
56     read();
57     work();
58     return 0;
59 }

POJ 1753
方法一

办法二代码(首先打个表):

图片 4图片 5

 1 void init() {
 2     for(int i=1; i<=16; i++) {
 3         int v=0, k=1<<(i-1); v|=k;
 4         if((i+1)%4!=1) v|=k<<1;
 5         if((i-1)%4!=0) v|=k>>1;
 6         if(i>4)  v|=k>>4;
 7         if(i<13) v|=k<<4;
 8         printf("%d,",v);
 9     }
10 }

非常不好看的打表

然后就足以拿表去水了,当然直接判断也是能够的,丑。

图片 6图片 7

 1 #include <stdio.h>
 2 
 3 int field;
 4 int state[]={19,39,78,140,305,626,1252,2248,4880,10016,20032,35968,12544,29184,58368,51200};
 5 
 6 void read() {
 7     for(int i=0; i<4; i++) {
 8         for(int j=0; j<4; j++) {
 9             field<<=1;
10             if(getchar()=='b')
11                 field|=1;
12         }
13         getchar();
14     }
15 }
16 
17 void flip(int i) {
18     field^=state[i];
19 }
20 
21 bool check() {
22     return field==0x0000||field==0xFFFF;
23 }
24 
25 bool find(int n, int i) {
26     if(n==0) return check();
27     //if(i>=16) return false;
28     for(; i<16; i++) {
29         flip(i);
30         if(find(n-1,i+1))
31             return true;
32         flip(i);
33     }
34     return false;
35 }
36 
37 void work() {
38     for(int c=0; c<=16; c++)
39         if(find(c,0)) {
40             printf("%d\n", c);
41             return;
42         }
43     puts("Impossible");
44 }
45 
46 int main() {
47     read();
48     work();
49     return 0;
50 }

POJ 1753
方法二

二、枚举

  一、那题应该简单想搜寻,当然枚举也是相比较简单能体会领会的。大家依然像前面方法二这样位压缩成八个数,假设无法压成多少个int的话那题当然也用持续枚举。需求思虑的是怎样贯彻$C^i_{16}$,也就是$16$个选$i$个$(i\in
[0,
16])$,考虑本身选哪多少个棋子也象征成0/1,接纳翻转的棋类作者用壹代表,比如要挑选第3个、第1个、第多少个和第伍个,那正是110十一的情状。那样枚举就很有益于了,枚举值范围0x0000~0xFFFF。

  二、同样像上边方法二那么打个表,对于每种枚举的意况,用位与运算求出哪个位是1(哪个棋子要扭转),然后根据打表的数码对输入的棋盘进行异或运算。进度中对扭曲后棋盘全黑或全白的情事求最少翻转数。

  3、能够随手再打 一<<0 ~
1<<15 的表。

图片 8图片 9

 1 #include <stdio.h>
 2 
 3 int field;
 4 int state[]={19,39,78,140,305,626,1252,2248,4880,10016,20032,35968,12544,29184,58368,51200};
 5 int bit[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
 6 
 7 void read() {
 8     for(int i=0; i<4; i++) {
 9         for(int j=0; j<4; j++) {
10             field<<=1;
11             if(getchar()=='b')
12                 field|=1;
13         }
14         getchar();
15     }
16 }
17 
18 bool check() {
19     return field==0x0000||field==0xFFFF;
20 }
21 
22 int minn=0xFF;
23 void work() {
24     for(int flip=0; flip<=0xFFFF; flip++) {
25         int temp=field, cnt=0;
26         for(int i=0; i<16; i++)
27             if(flip&bit[i]) {// flip&(1<<i)
28                 field^=state[i];
29                 ++cnt;
30             }
31         if(check()&&minn>cnt) minn=cnt;
32         field=temp;
33     }
34 }
35 
36 void print() {
37     if(minn==0xFF) puts("Impossible");
38     else printf("%d\n", minn);
39 }
40 
41 int main() {
42     read();
43     work();
44     print();
45     return 0;
46 }

POJ 1753
枚举

叁、高斯消元法

  一、基本想法是,令a=棋盘状态矩阵,b=最后各棋子的处境,ax=b解出x=要扭转的棋子,数一下x内部1的数码便是扭曲的棋类数了。因为最后状态能够是全黑或全白,因而要求对b取几遍值,做四次消元。

  2、可是你会意识,那题会平时出现无穷多解的动静,也正是存在任意变元。因而要求枚举or搜索那一个自由变元的值。

  (代码近年来没交,待更新)

 

——原创by
BlackStorm,转发请注解出处。

本文地址:http://www.cnblogs.com/BlackStorm/p/5231470.html

相关文章