对于npc问题,我们似乎只能用搜索(或状压dp)。
但是,有时候,搜索的期望得分是满分,比如说,当dancing links跳舞的时候。
dancing link 作为双向链表,拥有优秀的性质,快速的删除和恢复,任何熟练掌握链表的人都可以轻易上手,更重要的是,它为搜索省去大量回朔时间,并且方便启发式进行(只需加估价数组(代码中s)),优美的操作就像绚丽的舞步。
由于是矩阵,所以采用十字链表(up,down,left,right) c记录列号,t记录行号,s记录该列还有多少节点(尽量选择节点少进行拓展)
poj 3740(未加启发式) 219ms
poj 3740(加启发式) 172ms
c++版
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
int g[100][500];
int l[200000],r[200000],u[200000],d[200000],R[200000],C[200000];
int row[200000],clo[200000],v[200000];
int n,m,ss;
int ori()
{
++ss;
l[ss]=r[ss]=u[ss]=d[ss]=ss,R[ss]=C[ss]=0;
return ss;
}
void linkud(int x,int y)
{
d[x]=y,u[y]=x;
}
void linklr(int x,int y)
{
r[x]=y,l[y]=x;
}
void add(int x,int y)
{
ori();
R[ss]=row[x],C[ss]=clo[y];
int last=u[clo[y]];
linkud(last,ss),linkud(ss,clo[y]);
last=l[row[x]];
linklr(last,ss),linklr(ss,row[x]);
}
void build()
{
ss=0;
for (int i=1;i<=n;i++) row[i]=ori();
for (int i=0;i<=m;i++) clo[i]=ori();
for (int i=1;i<n;i++) linkud(row[i],row[i+1]);
linkud(row[n],row[1]);
for (int i=0;i<m;i++) linklr(clo[i],clo[i+1]);
linklr(clo[m],clo[0]);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (g[i][j]) add(i,j);
}
void del(int x)
{
linklr(l[x],r[x]);
for (int i=x;d[i]!=x;) {
i=d[i];
for (int y=i;r[y]!=i;) {
y=r[y];
if (R[y] && C[y]) linkud(u[y],d[y]);
}
}
}
void rel(int x)
{
linklr(l[x],x),linklr(x,r[x]);
for (int i=x;u[i]!=x;) {
i=u[i];
for (int y=i;l[y]!=i;) {
y=l[y];
if (R[y] && C[y])
linkud(u[y],y),linkud(y,d[y]);
}
}
}
bool DLX(int s,int step)
{
if (r[s]==s) return 1;
int x;
x=r[s],del(x);
for (int i=x;d[i]!=x;) {
i=d[i];
// cout<<'!'<<i<<endl;
for (int y=i;r[y]!=i;) {
y=r[y];
if (R[y] && C[y]) del(C[y]);
}
v[R[i]]=1;
if (DLX(s,step+1)) return 1;
v[R[i]]=0;
for (int y=i;l[y]!=i;) {
y=l[y];
if (R[y] && C[y]) rel(C[y]);
}
}
rel(x);
return 0;
}
int main() {
for (;scanf("%d%d",&n,&m)==2;) {
// cout<<n<<' '<<m<<endl;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
scanf("%d",&g[i][j]);
build();
if (DLX(clo[0],0)) {
printf("Yes, I found it\n");
}
else {
printf("It is impossible\n");
}
}
return 0;
}