今天刷了两个拖了好几天的题,写完发现好简单,网络上有好几种方法,枚举,BFS...我只会暴力枚举+BFS(最简单的)(/ □ \)。
HDU 1753 Flip Game
题目的大概意思就是给一个棋盘,例如
bwbw
bwww
wwwb
wwwb (b指black,w指white五五开)
可以翻转一个棋子,而且棋子的周围(上下左右)都会翻转,问至少翻转多少次可以将棋盘变成纯色(纯黑或者纯白)
思路:因为每个棋子翻转0次和翻转2次,即翻转偶数次是一样的结果。奇数同理。
棋盘为4✖4,所以有16个棋子,我们可以枚举只翻转棋子的数目0~16.
一共会枚举.
代码如下:
#include<cstdio>
#include <iostream>
using namespace std;
#include<cstring>
int chess[16+5][16+5];
bool flag=0;
int step; //枚举步数,从0~16步
int rf[5]={-1,0,1,0,0}; //上,右,下,左,自身 行
int cf[5] ={0,1,0,-1,0} ;//上,右,下,左,自身 列
bool isover()
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(chess[i][j]!=chess[1][1])
return false;
return true;
}
void fz(int r,int c)
{
for(int i=0;i<=4;i++)
{
chess[r+rf[i]][c+cf[i]]=!chess[r+rf[i]][c+cf[i]];
}
}
void bfs(int r,int c,int deep)
{
if(deep==step)
{
flag=isover();
return ;
}
if(flag || r==5) //flag==1已经完成,row==5已经出棋盘
{
return;
}
fz(r,c); //翻转
if(c<4)
{
bfs(r,c+1,deep+1);
}
else
{
bfs(r+1,1,deep+1);
}
fz(r,c); //假如第一个不翻转,就将第一个翻转回原样
if(c<4)
{
bfs(r,c+1,deep);
}
else
{
bfs(r+1,1,deep);
}
return;
}
int main()
{
char ch;
memset(chess,0,sizeof(chess));
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%c",&ch);
if(ch=='b')
chess[i][j]=1;
}
getchar();
}
for(int i=0;i<=16;i++)
{
step=i;
bfs(1,1,0);
if(flag)
break;
}
if(flag)
printf("%d\n",step);
else
printf("Impossible\n");
return 0;
}
HDU 2965
这题和上面的翻转棋子类似,只是翻转冰箱的门把手,一共16个门把手,也是可以翻转一次,但是这次如果翻转第i行,第j列的门把手,整个行和整个列的门把手都会被翻转。只不过这次不仅要输出最小步数,还要输出每步翻转的地方是那里。
思路:我们可以类似上面的方法枚举看,只要在改变判flag 的条件,然后在翻转的时候用一个数组记录一下i,j行列就好了。代码和上面很像。
代码如下:
#include<cstdio>
#include<cstring>
#define maxn 1000000
int door[4+5][4+5];
bool flag=false;
int num=0,step=0; //num用于记录开关的过程,两个为一个位置 ,step用于枚举步数
int s[maxn]; //记录开关门的过程
bool isover()
{
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
{
if(door[i][j]==1)
return false;
}
return true;
}
void fz(int r,int c,int x) //r是行,c是列
{
x+=1; //第一步时x也就是deep是等于step-1;
s[x*2-1]=r;
s[x*2]=c;
for(int i=1;i<=4;i++)
{
door[r][i]=!door[r][i];
door[i][c]=!door[i][c];
}
door[r][c]=!door[r][c];
}
void dfs(int r,int c,int deep)
{
if(deep==step)
{
flag=isover();
return ;
}
if(flag||r>=5)
{
return;
}
fz(r,c,deep);
if(c<4)
dfs(r,c+1,deep+1);
else
dfs(r+1,1,deep+1);
fz(r,c,deep);
if(c<4)
dfs(r,c+1,deep);
else
dfs(r+1,1,deep);
return ;
}
int main()
{
char ch;
memset(door,0,sizeof(door));
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%c",&ch);
if(ch=='+') //+代表关闭,1代表关闭
door[i][j]=1;
}
getchar();
}
/*for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
printf("%d ",door[i][j]);
}
printf("\n");
}*/
for(int i=0;i<=16;i++)
{
step=i;
dfs(1,1,0);
if(flag)
break;
}
if(flag)
{
printf("%d\n",step);
for(int i=1;i<=step*2;i++)
{
if(i&1==1) //为奇数
printf("%d ",s[i]);
else
printf("%d\n",s[i]);
}
}
else
printf("impossible\n");
return 0;
}
emmm蓝桥杯,校赛,省赛在即,希望自己能加油多刷一点题!