对于npc问题,我们似乎只能用搜索(或状压dp)。
但是,有时候,搜索的期望得分是满分,比如说,当dancing links跳舞的时候。
dancing link 作为双向链表,拥有优秀的性质,快速的删除和恢复,任何熟练掌握链表的人都可以轻易上手,更重要的是,它为搜索省去大量回朔时间,并且方便启发式进行(只需加估价数组(代码中s)),优美的操作就像绚丽的舞步。
由于是矩阵,所以采用十字链表(up,down,left,right) c记录列号,t记录行号,s记录该列还有多少节点(尽量选择节点少进行拓展)
poj 3740(未加启发式) 219ms
var n,m,ss:longint; flag:boolean; u,d,r,l,c,t:array[0..50000]of longint; procedure link(x,y:longint); begin inc(ss);c[ss]:=y;t[ss]:=x; l[ss]:=l[x];r[l[x]]:=ss;l[x]:=ss; u[ss]:=u[y];d[u[y]]:=ss;u[y]:=ss end; procedure del(x:longint); var i,j:longint; begin r[l[x]]:=r[x];l[r[x]]:=l[x]; i:=x; while d[i]<>x do begin i:=d[i]; j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then begin u[d[j]]:=u[j];d[u[j]]:=d[j] end end end end; procedure rel(x:longint); var i,j:longint; begin r[l[x]]:=x;l[r[x]]:=x; i:=x; while u[i]<>x do begin i:=u[i]; j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then begin u[d[j]]:=j;d[u[j]]:=j end end end end; procedure dfs(k:longint); var i,j,x:longint; begin if r[0]=0 then begin flag:=true;exit end; x:=r[0];del(x);i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then del(c[j]) end; dfs(k+1); if flag then exit; j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then rel(c[j]) end end; rel(x) end; procedure origin; var i:longint; begin fillchar(l,sizeof(l),0);fillchar(r,sizeof(r),0); fillchar(u,sizeof(u),0);fillchar(d,sizeof(d),0); fillchar(c,sizeof(c),0);fillchar(t,sizeof(t),0); r[0]:=1;l[0]:=m; for i:=1 to m do begin l[i]:=i-1;r[i]:=i+1;u[i]:=i;d[i]:=i end; r[m]:=0; for i:=m+1 to n+m do begin l[i]:=i;r[i]:=i end; ss:=n+m end; procedure init; var i,j,x:longint; begin readln(n,m); origin; for i:=1 to n do begin for j:=1 to m do begin read(x); if x=1 then link(i+m,j) end; readln end; for i:=1 to m do d[u[i]]:=i; for i:=m+1 to m+n do r[l[i]]:=i; flag:=false; dfs(0); if flag then writeln('Yes, I found it') else writeln('It is impossible') end; begin while not(seekeof) do init end.
poj 3740(加启发式) 172ms
var n,m,ss:longint; flag:boolean; u,d,r,l,c,t:array[0..50000]of longint; s:array[1..300]of longint; procedure link(x,y:longint); begin inc(ss);c[ss]:=y;t[ss]:=x; l[ss]:=l[x];r[l[x]]:=ss;l[x]:=ss; u[ss]:=u[y];d[u[y]]:=ss;u[y]:=ss; inc(s[y]) end; procedure del(x:longint); var i,j:longint; begin r[l[x]]:=r[x];l[r[x]]:=l[x]; i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then begin u[d[j]]:=u[j];d[u[j]]:=d[j]; dec(s[c[j]]) end end end end; procedure rel(x:longint); var i,j:longint; begin r[l[x]]:=x;l[r[x]]:=x; i:=x; while u[i]<>x do begin i:=u[i];j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then begin u[d[j]]:=j;d[u[j]]:=j; inc(s[c[j]]) end end end end; procedure dfs(k:longint); var i,j,x,y,min:longint; begin if r[0]=0 then begin flag:=true;exit end; x:=0;min:=maxlongint;y:=0; while r[x]<>0 do begin x:=r[x]; if s[x]<min then begin min:=s[x];y:=x end end; x:=y;del(x);i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then del(c[j]) end; dfs(k+1); if flag then exit; j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then rel(c[j]) end end; rel(x) end; procedure origin; var i:longint; begin fillchar(l,sizeof(l),0);fillchar(r,sizeof(r),0); fillchar(u,sizeof(u),0);fillchar(d,sizeof(d),0); fillchar(c,sizeof(c),0);fillchar(t,sizeof(t),0); fillchar(s,sizeof(s),0); r[0]:=1;l[0]:=m; for i:=1 to m do begin l[i]:=i-1;r[i]:=i+1;u[i]:=i;d[i]:=i end; r[m]:=0; for i:=m+1 to n+m do begin l[i]:=i;r[i]:=i end; ss:=n+m end; procedure init; var i,j,x:longint; begin readln(n,m); origin; for i:=1 to n do begin for j:=1 to m do begin read(x); if x=1 then link(i+m,j) end; readln end; for i:=1 to m do d[u[i]]:=i; for i:=m+1 to m+n do r[l[i]]:=i; flag:=false; dfs(0); if flag then writeln('Yes, I found it') else writeln('It is impossible') end; begin while not(seekeof) do init; end.
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; }