题目:连连看
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
Input
输入数据有多组。每组数据的第一行有两个正整数n,m(0<n<=1000,0<m<1000),分别表示棋盘的行数与列数。在接下来的n行中,每行有m个非负整数描述棋盘的方格分布。0表示这个位置没有棋子,正整数表示棋子的类型。接下来的一行是一个正整数q(0<q<50),表示下面有q次询问。在接下来的q行里,每行有四个正整数x1,y1,x2,y2,表示询问第x1行y1列的棋子与第x2行y2列的棋子能不能消去。n=0,m=0时,输入结束。
注意:询问之间无先后关系,都是针对当前状态的!
Output
每一组输入数据对应一行输出。如果能消去则输出"YES",不能则输出"NO"。
Sample Input
3 4
1 2 3 4
0 0 0 0
4 3 2 1
4
1 1 3 4
1 1 2 4
1 1 3 3
2 1 2 4
3 4
0 1 4 3
0 2 4 1
0 0 0 0
2
1 1 2 4
1 3 2 3
0 0
Sample Output
YES
NO
NO
NO
NO
YES
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1001;
int n,m,sign;//sign作为如何输出的标志,为0输出no,为1输出yes
int a[N][N];
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
bool check(int nowx,int nowy,int pos,int endx,int endy)
{//nowx代表现在的横坐标,nowy代表现在的纵坐标,endx和endy代表最终的坐标
int x=endx-nowx; //x和y记录差值
int y=endy-nowy;
if(x!=0) x=x/abs(x);//不为0的话,可以除以自身的绝对值得到正1或者负1,也就是代表着走的方向
if(y!=0) y=y/abs(y);
if(x==dir[pos][0]&&y==dir[pos][1])//如果跟当前位置的方向一致,说明连线到目前为止没有拐点
return true;
else
return false;
}
void dfs(int nowx,int nowy,int step,int pos,int endx,int endy)//step记录转折次数,pos记录方向
{
if(sign) return;
if(nowx>n||nowx<1||nowy>m||nowy<1||step>2)
return;
if(nowx==endx&&nowy==endy)
{
sign=1;
return;
}
if(step==2&&!check(nowx,nowy,pos,endx,endy))//当转折了两次以后,check的值还是为0,也就是又出现了拐点,不合题意,return
{
return;
}
if(a[nowx][nowy]!=0)
return;
for(int i=0;i<4;i++)
{
int nextx=nowx+dir[i][0];
int nexty=nowy+dir[i][1];
if(i==pos)//方向一致,没有拐点
dfs(nextx,nexty,step,pos,endx,endy);
else
dfs(nextx,nexty,step+1,i,endx,endy);//拐点加一
}
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF&&(n||m))//这里是说n,m不能为0
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&a[i][j]);
}
}
int b;
scanf("%d",&b);
while(b--)
{
sign=0;
int x0,y0,x2,y2;
scanf("%d %d %d %d",&x0,&y0,&x2,&y2);//不用y1是因为y1在math.h里定义过,是函数
if(a[x0][y0]==0||a[x0][y0]!=a[x2][y2])//排除前后为空和不相等的情况
{
printf("NO\n");
continue;
}
for(int i=0;i<4;i++)
{
int dx=x0+dir[i][0];
int dy=y0+dir[i][1];
dfs(dx,dy,0,i,x2,y2);//刚开始拐点数记为0
}
if(sign)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
这是dfs的做法,实际上还可以用bfs的做法做出来。请读者盆友们自行思考哦~
题目-Black And White
In mathematics, the four color theorem, or the four color map theorem, states that, given any separation of a plane into contiguous regions, producing a figure called a map, no more than four colors are required to color the regions of the map so that no two adjacent regions have the same color.
— Wikipedia, the free encyclopedia
In this problem, you have to solve the 4-color problem. Hey, I’m just joking.
You are asked to solve a similar problem:
Color an N × M chessboard with K colors numbered from 1 to K such that no two adjacent cells have the same color (two cells are adjacent if they share an edge). The i-th color should be used in exactly ci cells.
Matt hopes you can tell him a possible coloring.
Input
The first line contains only one integer T (1 ≤ T ≤ 5000), which indicates the number of test cases.
For each test case, the first line contains three integers: N, M, K (0 < N, M ≤ 5, 0 < K ≤ N × M ).
The second line contains K integers ci (ci > 0), denoting the number of cells where the i-th color should be used.
It’s guaranteed that c1 + c2 + · · · + cK = N × M .
Output
For each test case, the first line contains “Case #x:”, where x is the case number (starting from 1).
In the second line, output “NO” if there is no coloring satisfying the requirements. Otherwise, output “YES” in one line. Each of the following N lines contains M numbers seperated by single whitespace, denoting the color of the cells.
If there are multiple solutions, output any of them.
Sample Input
4
1 5 2
4 1
3 3 4
1 2 2 4
2 3 3
2 2 2
3 2 3
2 2 2
Sample Output
Case #1:
NO
Case #2:
YES
4 3 4
2 1 2
4 3 4
Case #3:
YES
1 2 3
2 3 1
Case #4:
YES
1 2
2 3
3 1
思路:
从左上角搜索到右下角,只需要判断是否和上面与左面的砖块颜色是否相同。
理解一下,按顺序放进去,就只要判断左边和上面啦啦啦
而当剩下的砖块数量+1小于某种颜色的数量的两倍,这时必然会相邻。
比如说一开始的时候,n=m=3,然后红色的有6个,在放完5个以后,无论放哪里都会有相邻情况,如下图:
而在你遍历完一行以后,第一行的三个颜色可以看成是已经填进去了的。此时,假设有种颜色是5个,那么放完四个以后,无论在哪放,也会有相邻的情况。所以这个时候也就是 dfs(x,y,sum-1)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=26;
int a[N],sign,vis[N][N],k,n,m,num;
bool check(int x,int y,int col)//第x行,第y列,填充的颜色为col
{//先把第一列,第一行的特殊情况单独考虑
if(x==1&&y==1)//第一行第一列的格子
{
return 1;
}
if(x==1)
{
if(vis[x][y-1]!=col)//相邻的上面的格子的颜色与检查的格子的颜色是否相等
{
return 1;
}
else
return 0;
}
if(y==1)
{
if(vis[x-1][y]!=col)//相邻的左边的格子的检查
{
return 1;
}
else
return 0;
}
if(vis[x-1][y]!=col&&vis[x][y-1]!=col)
{
return 1;
}
else
return 0;
}
void Dfs(int x,int y,int sum)//第x行,第y列,sum个格子
{
if(sign)
return;
for(int i=1;i<=k;i++)
{
if((sum+1)/2<a[i])
return;
}
for(int i=1;i<=k;i++)
{
if(check(x,y,i)&&a[i]>0)
{
vis[x][y]=i;//格子用对应的颜色标记好
a[i]--;//涂好一个少一个
if(x==n&&y==m&&sign==0)//遍历到了最后一行的最后一个格子
{
sign=1;
printf("Case #%d:\nYES\n",num);
for(int j=1;j<=n;j++)
{
cout<<vis[j][1];//回溯
for(int jj=2;jj<=m;jj++)
{
cout<<' '<<vis[j][jj];
}
cout<<endl;
}
}
else if(y==m)//列到了最后一列
{
Dfs(x+1,1,sum-1);//行加一,总数减一(如果不明白再看看思路哦)
}
else{
Dfs(x,y+1,sum-1);
}
//否则,恢复原状
vis[x][y]=0;
a[i]++;
}
}
}
int main()
{
int T;
scanf("%d",&T);
memset(vis,0,sizeof(vis));
for(int i=1;i<=T;i++)
{
sign=0;
num++;
scanf("%d %d %d",&n,&m,&k);
memset(a,0,sizeof(a));
for(int i=1;i<=k;i++)
{
scanf("%d",&a[i]);
}
Dfs(1,1,n*m);
if(sign==0)
printf("Case #%d:\nNO\n",num);
}
return 0;
}