【BZOJ 1088 扫雷Mine】模拟

http://www.lydsy.com/JudgeOnline/problem.php?id=1088

2*N的扫雷棋盘,第二列的值a[i]记录第 i 个格子和它8连通的格子里面雷的数目。

第一列的雷可能有多种方案满足第二列的数的限制,根据第二列的信息确定第一列雷有多少种摆放方案。

设第一列的值为b[i],不难得出以下递推关系

b[0] + b[1] = a[0]

b[0] + b[1] + b[2] = a[1]

...

b[i] = a[i-1] - a[i-2] + b[i-3]
或 b[i] = a[i-1] - b[i-1] - b[i-2]

由此发现,b[0]、b[1]确定了,后续的b[i]也由递推式唯一的确定了。而又有b[0]+b[1] = a[0]的限制条件,故可根据a[0]的值枚举b[0], b[1]的组合,然后顺次求出b[i], 判断每个b[i]值是否合法,一旦发现不合法,则此种枚举情况不成立。

程序流程图如下(这里的“合法”判断与具体位置有关,如a[0], a[n-1] <3, a[n-1] == b[n-1] + b[n-2]):

代码如下(为了直观表达流程图,用了goto语句):

 1 #include <cstdio>
 2 using namespace std;
 3 
 4 int n;
 5 int a[10005];
 6 int b[10005];
 7 
 8 int main()
 9 {
10     scanf("%d", &n);
11     for(int i=0; i<n; i++){
12         scanf("%d", &a[i]);
13     }
14     int cnt = 0;
15 
16     for(int i=0; i<n; i++){ //非法 
17         if(a[i]<0 || a[i]>3){
18             goto L;
19         }
20     }
21     if(a[n-1]==3 || a[0] == 3){ //非法 
22         goto L;
23     }
24     
25     if(a[0] == 0) b[0] = b[1] = 0;
26     else if(a[0] == 2) b[0] = b[1] = 1; 
27     
28     if(a[0] == 1) goto B;
29     
30     b[2] = a[1] - a[0]; //0或2的情况 
31     if(b[2] < 0 || b[2] > 1){
32         goto L;
33     }
34     for(int i=3; i<n; i++){
35         b[i] = a[i-1] - a[i-2] + b[i-3];
36         if(b[i] < 0 || b[i] > 1){
37             goto L;
38         }
39     }
40     if(b[n-1] + b[n-2] != a[n-1]) //检查最后一个a 
41         goto L;
42     printf("1\n");
43     return 0;    
44 
45 B:    b[0] = 0; b[1] = 1; //01或10的情况 
46     b[2] = a[1] - a[0];
47     if(b[2] < 0 || b[2] > 1){
48         goto L1;
49     }
50     for(int i=3; i<n; i++){
51         b[i] = a[i-1] - a[i-2] + b[i-3];
52         if(b[i] < 0 || b[i] > 1){
53             goto L1;
54         }
55     }
56     if(b[n-1] + b[n-2] != a[n-1])
57         goto L1;
58     cnt++;
59         
60 L1:    b[0] = 1; b[1] = 0; //试探另一种 
61     b[2] = a[1] - a[0];
62     if(b[2] < 0 || b[2] > 1){
63         goto L;
64     }
65     for(int i=3; i<n; i++){
66         b[i] = a[i-1] - a[i-2] + b[i-3];
67         if(b[i] < 0 || b[i] > 1){
68             goto L;
69         }
70     }
71     if(b[n-1] + b[n-2] != a[n-1])
72         goto L;
73     cnt++;
74         
75 L:    printf("%d\n", cnt);
76     return 0;
77 
78 }
BZOJ 1088

 

posted @ 2016-04-12 15:09  helena_wang  阅读(...)  评论(... 编辑 收藏