一.画家问题
有一个正方形的墙,由N*N个正方形的砖组成,其中一些砖是白色的,另外一些砖是黄色的。Bob是个画家,想把全部的砖都涂成黄色。但他的画笔不好使。当他用画笔涂画第(i, j)个位置的砖时, 位置(i-1, j)、 (i+1, j)、 (i, j-1)、 (i, j+1)上的砖都会改变颜色。请你帮助Bob计算出最少需要涂画多少块砖,才能使所有砖的颜色都变成黄
输入第一行是一个整数n (1≤n ≤15),表示墙的大小。接下来的n行表示墙的初始状态。每一行包含n个字符。第i行的第j个字符表示位于位置(i,j)上的砖的颜色。“w”表示白砖,“y”表示黄砖。输出一行,如果Bob能够将所有的砖都涂成黄色,则输出最少需要涂画的砖数,否则输出“inf”。
样例输入:
5
wwwww
wwwww
wwwww
wwwww
wwwww
代码如下:
#include <iostream> #include <fstream> #include <stdlib.h> #include <cstdio> #include <algorithm> using namespace std; int wall[20][20]={0}; //存储原始状态的函数 int press[20][20]={0};//存储处理方法的函数 int n=0,minn=9999,count0=0;//n为规模,minn为最小处理数 bool flag =0; //该变量表示问题是否有解 void init(){ //初始化函数,涂为1,未涂为0; 这个函数没有问题 cin>>n; for (int i=1;i<=n;i++){ for (int j=1;j<=n;j++){ char t; cin >> t; if(t=='w') wall[i][j]=0; else wall[i][j]=1; } } } bool guess(){ for (int i=1;i<n;i++){ for (int j=1;j<=n;j++){ press[i+1][j]=(wall[i][j] + press[i][j] + press[i][j - 1] + press[i][j + 1] + press[i - 1][j]+1) % 2;//除了第一行,其余每一行都可以根据上一行唯一确定其涂色方式;这一行就是确定解的方程 } } for (int j=1;j<=n;j++){ if((press[n][j - 1] + press[n][j + 1] + press[n-1][j]+press[n][j]) % 2 == wall[n][j]) //每一行都是根据上一行确定的,所以我们可以根据最后一行是否满足要求来判断问题是否有解 return false; } return true; } void solve() { while (true) { if (guess()) { for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { if (press[i][j]==1)count0++; } minn = min(count0, minn); count0 = 0; flag = 1; } for (int i = 2; i <= n; i++) for (int j = 1; j <= n; j++) press[i][j] = 0; press[1][1]++; //对第一行进行枚举 int c = 1; while (press[1][c] > 1) { press[1][c] = 0; press[1][++c]++; } if (c == n + 1) break; } } int main(){ init(); solve(); if(flag==1) cout << minn << endl; else cout << "inf" << endl; return 0; }
二.拨钟问题
有9个时钟,排成一个3*3的矩阵。
|-------| |-------| |-------|
| | | | | | |
|---O | |---O | | O |
| | | | | |
|-------| |-------| |-------|
A B C
|-------| |-------| |-------|
| | | | | |
| O | | O | | O |
| | | | | | | | |
|-------| |-------| |-------|
D E F
|-------| |-------| |-------|
| | | | | |
| O | | O---| | O |
| | | | | | | |
|-------| |-------| |-------|
G H I
(图 1)
现在需要用最少的移动,将9个时钟的指针都拨到12点的位置。共允许有9种不同的移动。如下表所示,每个移动会将若干个时钟的指针沿顺时针方向拨动90度。
移动 影响的时钟
1 ABDE
2 ABC
3 BCEF
4 ADG
5 BDEFH
6 CFI
7 DEGH
8 GHI
9 EFHI
输入9个整数,表示各时钟指针的起始位置,相邻两个整数之间用单个空格隔开。其中,0=12点、1=3点、2=6点、3=9点。输出输出一个最短的移动序列,使得9个时钟的指针都指向12点。按照移动的序号从小到大输出结果。相邻两个整数之间用单个空格隔开。样例输入
3 3 0
2 2 2
2 1 2
样例输出
4 5 8 9
代码如下:
#include<cstdio> using namespace std; //同上一题,我们发现除了第一行需要枚举外,第二行第三行中的每个格子基本都可以通过已知条件得出。 int z[10],i[10],sum; int main() { for(int j=1;j<=9;j++)scanf("%d",&z[j]); for(i[1]=0;i[1]<4;i[1]++) for(i[2]=0;i[2]<4;i[2]++) for(i[3]=0;i[3]<4;i[3]++) { i[4]=(4-(z[1]+i[1]+i[2])%4)%4; i[5]=(4-(z[2]+i[1]+i[2]+i[3])%4)%4; i[6]=(4-(z[3]+i[2]+i[3])%4)%4; i[7]=(4-(z[4]+i[1]+i[4]+i[5])%4)%4; i[9]=(4-(z[6]+i[3]+i[5]+i[6])%4)%4; i[8]=(4-(z[8]+i[5]+i[7]+i[9])%4)%4;//这里要注意第8个格子是由第九个格子决定的 sum=0;//判断是否可解 sum+=(z[1]+i[1]+i[2]+i[4])%4; sum+=(z[2]+i[1]+i[2]+i[3]+i[5])%4; sum+=(z[3]+i[2]+i[3]+i[6])%4; sum+=(z[4]+i[1]+i[4]+i[5]+i[7])%4; sum+=(z[5]+i[1]+i[3]+i[5]+i[7]+i[9])%4; sum+=(z[6]+i[3]+i[5]+i[6]+i[9])%4; sum+=(z[7]+i[4]+i[7]+i[8])%4; sum+=(z[8]+i[5]+i[7]+i[8]+i[9])%4; sum+=(z[9]+i[6]+i[8]+i[9])%4; if(sum==0){for(int j=1;j<=9;j++)while(i[j]--)printf("%d ",j);return 0;} } }
三.特殊密码锁
描述
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。
然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。
当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。
输入两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。输出至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。样例输入
011 000
样例输出
1
代码如下:
#include <iostream> #include <fstream> #include <stdlib.h> #include <cstdio> #include <algorithm> #include <string> #include <memory.h> using namespace std; //该题较简单,只需枚举第一个格子是否需要改变(两种情况),比较两种情况的大小即可 const int maxn = 35; int key[maxn], pwd[maxn], press[maxn], aft[maxn], leng, success = 0, step = 0, minstep = 9999;//press-whether to change the status;aft-status after the press void init() { string s1, s2; cin >> s1 >> s2; int l1 = s1.length(); for (int i = 0; i < l1; i++) { key[i + 1] = s1[i] - '0'; pwd[i + 1] = s2[i] - '0'; aft[i + 1] = s1[i] - '0'; } leng = l1; } void solve() { for (int op = 0; op <= 1; op++) { memset(press, 0, sizeof(int)*maxn); step = 0; press[1] = op; aft[1] ^= op; aft[2] ^= op; step += op; for (int i = 2; i <= leng; i++) { if (aft[i - 1] != pwd[i - 1]) { press[i] = 1; step++; } aft[i] ^= press[i]; aft[i-1] ^= press[i]; aft[i+1] ^= press[i]; if (i == leng && aft[i] == pwd[i]) { success = 1; minstep = min(step, minstep); } } for (int i = 1; i <= leng; i++)aft[i] = key[i]; } if (success)printf("%d\n", minstep); else printf("impossible\n"); } int main() { init(); solve(); return 0; }
期末苟住!!!