提交到ZOJ,WA了N次,终于修成正果^_^,排在第三位。
我的思路是这样的:
从S和T分别如图扩展,如果扩展过程相遇,直接返回可以消去,否则还得像箭头那样扫描,如果同时扫过黄色和蓝色,返回可以消去。
当然,这些过程中还有许多细节,请参阅源代码。
补充一点,这个代码改一改就可以做成连连看的游戏,不过少了判断死锁的模块和生成新游戏的模块。
/*
* ZOJ Problem Set - 2411 Link Link Look
* Analysis: BFS
* Author: mike-w
*/
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#define INPUT "input.txt"
#define SIZE 100
int grid[SIZE+2][SIZE+2];
bool mark[SIZE+2][SIZE+2];
/*
* 我的一个思路是BFS,可惜我写不出来==!
* 我的另一个思路是*&&^&$#$——一个说不清楚的办法...
* 具体实现是从起点和终点开始向上下左右四个方向延伸标记
* 然后再用一条直线扫描
*/
int click(int x1,int y1,int x2,int y2,int maxx,int maxy)
{
if(x1==x2&&y1==y2)
return 0;
if(grid[x1][y1]!=grid[x2][y2]) /* 方块颜色不同 */
return 0;
if(!grid[x1][y1]) /* 点击在空白处 */
return 0;
int rec1,rec2,rec3,rec4,i,j,v;
memset(mark,0,sizeof(mark));
mark[x1][y1]=mark[x2][y2]=1;
v=grid[x1][y1];
grid[x1][y1]=grid[x2][y2]=0;
/* 从 (x1,y1) 开始探索 */
for(i=1;x1+i<=maxx+1&&!grid[x1+i][y1];i++) /* 向下探索 */
if(mark[x1+i][y1])
return 2;
else mark[x1+i][y1]=1;
rec1=x1+i-1;
for(i=1;x1-i>=0&&!grid[x1-i][y1];i++) /* 向上探索 */
if(mark[x1-i][y1])
return 2;
else mark[x1-i][y1]=1;
rec2=x1-i+1;
for(i=1;y1+i<=maxy+1&&!grid[x1][y1+i];i++) /* 向右探索 */
if(mark[x1][y1+i])
return 2;
else mark[x1][y1+i]=1;
rec3=y1+i-1;
for(i=1;y1-i>=0&&!grid[x1][y1-i];i++) /* 向左探索 */
if(mark[x1][y1-i])
return 2;
else mark[x1][y1-i]=1;
rec4=y1-i+1;
/* 从终点 (x2,y2) 开始探索 */
for(i=1;x2+i<=maxx+1&&!grid[x2+i][y2];i++) /* 向下探索 */
if(mark[x2+i][y2])
return 2;
else mark[x2+i][y2]=1;
for(i=1;x2-i>=0&&!grid[x2-i][y2];i++) /* 向上探索 */
if(mark[x2-i][y2])
return 2;
else mark[x2-i][y2]=1;
for(i=1;y2+i<=maxy+1&&!grid[x2][y2+i];i++) /* 向右探索 */
if(mark[x2][y2+i])
return 2;
else mark[x2][y2+i]=1;
for(i=1;y2-i>=0&&!grid[x2][y2-i];i++) /* 向左探索 */
if(mark[x2][y2-i])
return 2;
else mark[x2][y2-i]=1;
/* 开始“神奇地”扫描 */
for(i=rec2;i<=rec1;i++) /* 水平扫描 */
{
if(i==x1)
continue;
for(j=1;y1+j<=maxy+1&&!grid[i][y1+j];j++)
if(mark[i][y1+j]) /* 这时已经不需要再标记了 */
return 2;
for(j=1;y1-j>=0&&!grid[i][y1-j];j++)
if(mark[i][y1-j])
return 2;
}
for(i=rec4;i<=rec3;i++) /* 垂直扫描 */
{
if(i==y1)
continue;
for(j=1;x1+j<=maxx+1&&!grid[x1+j][i];j++)
if(mark[x1+j][i])
return 2;
for(j=1;x1-j>=0&&!grid[x1-j][i];j++) /* 其实这两个for只有一个做有用功 */
if(mark[x1-j][i])
return 2;
}
grid[x1][y1]=grid[x2][y2]=v; /* 恢复grid的值 */
return 0; /* 消掉0个 */
}
int main(void)
{
int nclick,n,m;
int x1,x2,y1,y2,i,j;
int dis=0;
/* freopen(INPUT,"r",stdin); */
while(scanf("%d%d",&n,&m)!=EOF&&m&&n)
{
dis=0;
memset(grid,0,sizeof(grid));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",grid[i]+j);
scanf("%d",&nclick);
while(nclick--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
dis+=click(x1,y1,x2,y2,n,m); /* click() 返回消去的方块数 */
}
printf("%d\n",dis);
}
return 0;
}
下面是第二个版本,做了一小点优化,不过还是20ms
/*
* ZOJ Problem Set - 2411 Link Link Look
* Analysis: BFS
* Author: mike-w
*/
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
#define INPUT "input.txt"
#define SIZE 100
int grid[SIZE+2][SIZE+2];
bool mark[SIZE+2][SIZE+2];
/*
* 我的一个思路是BFS,可惜我写不出来==!
* 我的另一个思路是*&&^&$#$——一个说不清楚的办法...
* 具体实现是从起点和终点开始向上下左右四个方向延伸标记
* 然后再用一条直线扫描
*/
int click(int x1,int y1,int x2,int y2,int maxx,int maxy)
{
if(x1==x2&&y1==y2)
return 0;
if(grid[x1][y1]!=grid[x2][y2]) /* 方块颜色不同 */
return 0;
if(!grid[x1][y1]) /* 点击在空白处 */
return 0;
int rec1,rec2,rec3,rec4,i,j,v;
memset(mark,0,sizeof(mark));
mark[x1][y1]=mark[x2][y2]=1;
v=grid[x1][y1];
grid[x1][y1]=grid[x2][y2]=0;
/* 从 (x1,y1) 开始探索 */
for(i=1;x1+i<=maxx+1&&!grid[x1+i][y1];i++) /* 向下探索 */
if(mark[x1+i][y1])
return 2;
else mark[x1+i][y1]=1;
rec1=x1+i-1;
for(i=1;x1-i>=0&&!grid[x1-i][y1];i++) /* 向上探索 */
if(mark[x1-i][y1])
return 2;
else mark[x1-i][y1]=1;
rec2=x1-i+1;
for(i=1;y1+i<=maxy+1&&!grid[x1][y1+i];i++) /* 向右探索 */
if(mark[x1][y1+i])
return 2;
else mark[x1][y1+i]=1;
rec3=y1+i-1;
for(i=1;y1-i>=0&&!grid[x1][y1-i];i++) /* 向左探索 */
if(mark[x1][y1-i])
return 2;
else mark[x1][y1-i]=1;
rec4=y1-i+1;
/* 从终点 (x2,y2) 开始探索 */
for(i=1;x2+i<=maxx+1&&!grid[x2+i][y2];i++) /* 向下探索 */
if(mark[x2+i][y2])
return 2;
else mark[x2+i][y2]=1;
for(i=1;x2-i>=0&&!grid[x2-i][y2];i++) /* 向上探索 */
if(mark[x2-i][y2])
return 2;
else mark[x2-i][y2]=1;
for(i=1;y2+i<=maxy+1&&!grid[x2][y2+i];i++) /* 向右探索 */
if(mark[x2][y2+i])
return 2;
else mark[x2][y2+i]=1;
for(i=1;y2-i>=0&&!grid[x2][y2-i];i++) /* 向左探索 */
if(mark[x2][y2-i])
return 2;
else mark[x2][y2-i]=1;
/* 开始“神奇地”扫描 */
for(i=rec2;i<=rec1;i++) /* 水平扫描 */
{
if(i==x1||y1==y2)
continue;
if(y2>y1)
{
for(j=1;y1+j<=maxy+1&&!grid[i][y1+j];j++)
if(mark[i][y1+j]) /* 这时已经不需要再标记了 */
return 2;
}
else
{
for(j=1;y1-j>=0&&!grid[i][y1-j];j++)
if(mark[i][y1-j])
return 2;
}
}
for(i=rec4;i<=rec3;i++) /* 垂直扫描 */
{
if(i==y1||x1==x2)
continue;
if(x2>x1)
{
for(j=1;x1+j<=maxx+1&&!grid[x1+j][i];j++)
if(mark[x1+j][i])
return 2;
}
else
{
for(j=1;x1-j>=0&&!grid[x1-j][i];j++)
if(mark[x1-j][i])
return 2;
}
}
grid[x1][y1]=grid[x2][y2]=v; /* 恢复grid的值 */
return 0; /* 消掉0个 */
}
int main(void)
{
int nclick,n,m;
int x1,x2,y1,y2,i,j;
int dis=0;
/* freopen(INPUT,"r",stdin); */
while(scanf("%d%d",&n,&m)!=EOF&&m&&n)
{
dis=0;
memset(grid,0,sizeof(grid));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",grid[i]+j);
scanf("%d",&nclick);
while(nclick--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
dis+=click(x1,y1,x2,y2,n,m); /* click() 返回消去的方块数 */
}
printf("%d\n",dis);
}
return 0;
}