Time Limit: 5 Sec Memory Limit: 128 MB
Description
Input
Output
Sample Input
2 3 3 1 1
2 2
3 3
2 3 3 1 1
1 1
2 2
Sample Output
Yes
No
HINT
题解
一个神奇的搜索。
首先对于走三格的情况,我们可以发现:一个矩阵中的所有点可以分为9个类别;每个类别中的点分别可以通过“走三格”的方法相互到达。如图:
0 1 2 0 1 2 3 4 5 3 4 5 6 7 8 6 7 8 那么在分类的情况下,我们考虑“走两格”的情况,如0跨过1到2,我们可以将这种改变看做0和1可以合并为2,所以题目就可化为:能不将所有(最多9种)点通过一系列合并得到一个和目标格子同类的点。矩阵大小为3*3。
看这数据范围,只有搜索了。那么我们考虑怎么表示搜索状态:考虑的只有9类那么就加一个简单的hash:将所有类别的个数用一个9位的大整数表示状态,再mod一个较大的素数,怕哈希一层有问题,我用了一个很傻的链表(毕竟我很弱)。
具体的边界问题代码中看会更清楚。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
#define mod 2000007
using namespace std;
int K,n,m,xd,yd,lei,size;
struct dian {int x,y;} d[12];
int to[12][12],num[2000010],pre[2500000],last[2500000],zz;
int f[2500000],pd[2500000];
//------------------------------------------------------------------------------
void init()
{
lei=((xd-1)%3*3+(yd-1)%3);
int i,j,p,x,y;
for(i=1;i<=K;i++) scanf("%d%d",&d[i].x,&d[i].y);
memset(to,-1,sizeof(to));
for(i=0;i<n;i++)//处理出所有可能的合并
for(j=0;j<m;j++)
{p=(i%3)*3+(j%3);
if(i>1&&j>1)
{x=((i-2)%3)*3+(j-2)%3; y=((i-1)%3)*3+(j-1)%3; to[p][y]=x;}
if(j>1)
{x=(i%3)*3+(j-2)%3; y=(i%3)*3+(j-1)%3; to[p][y]=x;}
if(i<n-2&&j>1)
{x=((i+2)%3)*3+(j-2)%3; y=((i+1)%3)*3+(j-1)%3; to[p][y]=x;}
if(i<n-2)
{x=((i+2)%3)*3+j%3; y=((i+1)%3)*3+j%3; to[p][y]=x;}
if(i<n-2 && j<m-2)
{x=((i+2)%3)*3+(j+2)%3; y=((i+1)%3)*3+(j+1)%3; to[p][y]=x;}
if(j<m-2)
{x=(i%3)*3+(j+2)%3; y=(i%3)*3+(j+1)%3; to[p][y]=x;}
if(i>1)
{x=((i-2)%3)*3+j%3; y=((i-1)%3)*3+j%3; to[p][y]=x;}
if(i>1&&j<m-2)
{x=((i-2)%3)*3+(j+2)%3; y=((i-1)%3)*3+(j+1)%3; to[p][y]=x;}
}
}
int find(int shu)
{
int w=shu%mod,i;
i=last[w];
while(i>0)
{if(num[i]==shu) return i;
i=pre[i];
}
zz++;
num[zz]=shu; pre[zz]=last[w]; last[w]=zz;
return zz;
}
int dfs(int shu,int ct)
{
int i,j,k,s[12],w=find(shu),now;
if(pd[w]) return f[w];
now=shu;
for(i=8;i>=0;i--)
{s[i]=now%10; now/=10;}
if(ct==1)//搜索的底线:当只剩一个棋子时。
{pd[w]=1;
if(s[lei]==1) return 1;
else return 0;
}
for(i=0;i<9;i++)
{if(!s[i]) continue;
for(j=0;j<9;j++)//常规的dfs套路。
{if(s[j]&&to[i][j]!=-1)
{now=0;
s[i]--; s[j]--; s[to[i][j]]++;
for(k=0;k<9;k++)
{now=now*10; now+=s[k];}
if(dfs(now,ct-1))
{pd[w]=1;
f[w]=1;
return 1;
}
s[i]++; s[j]++; s[to[i][j]]--;
}
}
}
pd[w]=1;
return 0;
}
void work()
{
int i,j,p,shu=0,tag=1,s[12];
memset(s,0,sizeof(s));
memset(f,0,sizeof(f));
memset(pd,0,sizeof(pd));
memset(last,0,sizeof(last));
for(i=1;i<=K;i++)
{p=(d[i].x-1)%3*3+(d[i].y-1)%3;
s[p]++;
}
for(i=0;i<9;i++)//K个棋子都是同类的,永远消不掉。
{if(s[i]==K) {tag=0; break;}}
if(tag==0) {printf("No\n"); return ;}
zz=0;
for(i=0;i<9;i++)
{shu=shu*10; shu+=s[i];}
if(dfs(shu,K)) printf("Yes\n");
else printf("No\n");
}
int main()
{
freopen("galaxy.in","r",stdin);
freopen("galaxy.out","w",stdout);
while(scanf("%d%d%d%d%d",&K,&n,&m,&xd,&yd)!=EOF)
{init(); work();}
return 0;
}