【搜索】[HDU1175]连连看
题目
分析:这道题看到的第一反应应该就是BFS或者DFS,裸的DFS、BFS显然会TLE,所以我就想用A*,不过好像并不好写启发函数。
枚举步数不行,就枚举边吧。因为允许有两次转折,所以最多有三条边枚举中间的一条边,然后进行check,这道题只用了两个for循环就AC了。
代码:
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 1000
int a[MAXN+10][MAXN+11],q,n,m,h[MAXN+10][MAXN+10],v[MAXN+10][MAXN+10],sx,sy,ex,ey;
bool check(){
int i,a,b;
a=min(sx,ex);
b=max(sx,ex);
for(i=1;i<=m;i++){
if(i<sy){
if(h[sx][sy-1]!=h[sx][i-1])
continue;
}
else if(i>sy){
if(h[sx][sy]!=h[sx][i])
continue;
}
if(i<ey){
if(h[ex][ey-1]!=h[ex][i-1])
continue;
}
else if(i>ey){
if(h[ex][ey]!=h[ex][i])
continue;
}
if(sy==i&&ey==i){
if(v[b-1][i]!=v[a][i])
continue;
}
else if(sy==i){
if(sx<ex){
if(v[ex][i]!=v[sx][i]);
continue;
}
else if(sx>ex){
if(v[sx-1][i]!=v[ex-1][i])
continue;
}
}
else if(ey==i){
if(sx>ex){
if(v[ex][i]!=v[sx][i]);
continue;
}
else if(sx<ex){
if(v[sx-1][i]!=v[ex-1][i])
continue;
}
}
else if(v[b][i]!=v[a-1][i])
continue;
return 1;
}
a=min(sy,ey);
b=max(sy,ey);
for(i=1;i<=n;i++){
if(i<sx){
if(v[i-1][sy]!=v[sx-1][sy])
continue;
}
else if(i>sx){
if(v[i][sy]!=v[sx][sy])
continue;
}
if(i<ex){
if(v[i-1][ey]!=v[ex-1][ey])
continue;
}
else if(i>ex){
if(v[i][ey]!=v[ex][ey])
continue;
}
if(sx==i&&ex==i){
if(h[i][b-1]!=h[i][a])
continue;
}
else if(sx==i){
if(sy<ey){
if(h[i][ey]!=h[i][sy])
continue;
}
else if(sy>ey){
if(h[i][sy-1]!=h[i][ey-1])
continue;
}
}
else if(ex==i){
if(sy>ey){
if(h[i][ey]!=h[i][sy])
continue;
}
else if(sy<ey){
if(h[i][sy-1]!=h[i][ey-1])
continue;
}
}
else if(h[i][b]!=h[i][a-1])
continue;
return 1;
}
return 0;
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)){
if(!n)
return 0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
scanf("%d",&a[i][j]);
h[i][j]=h[i][j-1]+a[i][j];
v[i][j]=v[i-1][j]+a[i][j];
}
scanf("%d",&q);
while(q--){
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
if(a[sx][sy]!=a[ex][ey]||!a[sx][sy]||!check())
puts("NO");
else
puts("YES");
}
}
}