代码是昨天写的,今天又试着做重复覆盖的DLX,发现根本写不下,出现了重重错误,我还以为我昨天误打误撞的代码很优咧,太自以为是了!这道HDOJ2828也是好题,它比我今天试写的HDOJ3957简单得多,最大的不同不是一个只是求一个YES/NO,另一个求的是最小dfs深度,而是3957的链表数据中的关系比2828复杂,所以dance实现部分的思想都是不一样的~
**尚未成功,菜鸟仍需努力~不想说revolution那个凝重的词。
// 第二个Dancing links,1Y,0ms,暂时排名第五,挺兴奋的! #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int NN=505; const int MM=51000; int n,m,cnt,R[MM],L[MM],U[MM],D[MM],C[MM],H[MM],flag[MM]; int S[NN],O[NN],V[NN]; void init()//这里的十字链表以灯为列,开关为行 { cnt=n; for (int i=0; i<=n; i++) { D[i]=U[i]=i; R[i]=i+1; L[i+1]=i; S[i]=0; } L[0]=n,R[n]=0; for (int i=1; i<=m; i++) V[i]=0; } void add_link(int i,int j,int t) { C[++cnt]=i; H[cnt]=j; S[i]++; flag[cnt]=t; //开关状态 D[cnt]=i; U[cnt]=U[i]; if (V[j]) R[cnt]=V[j],L[cnt]=L[V[j]]; else R[cnt]=L[cnt]=cnt; V[j]=cnt; U[D[cnt]]=cnt; D[U[cnt]]=cnt; R[L[cnt]]=cnt; L[R[cnt]]=cnt; } void remove(int c)//题意不同,这里remove有变,指的是删除c列 { L[R[c]]=L[c]; R[L[c]]=R[c]; for (int i=D[c]; i!=c; i=D[i]) { L[R[i]]=L[i]; R[L[i]]=R[i]; S[C[i]]--; } } void resume(int c) { for (int i=U[c]; i!=c; i=U[i]) { R[L[i]]=i; L[R[i]]=i; S[C[i]]++; } R[L[c]]=L[R[c]]=c; } bool dance() { if (!R[0]) { for (int i=1; i<m; i++) printf(O[i]==1?"ON ":"OFF "); puts(O[m]==1?"ON":"OFF"); return 1; } int c,s=MM,i,j; for (i=R[0]; i; i=R[i]) if (S[i]<s) s=S[c=i]; if (s==0) return 0; //s==0说明没有开关能使灯c处于ON的状态了 R[L[c]]=R[c]; L[R[c]]=L[c]; //这里只需删去列指针c即可 for (i=D[c]; i!=c; i=D[i]) { O[H[i]]=flag[i];//记录答案 for (int j=R[i]; j!=i; j=R[j]) { if (flag[j]==flag[i]) remove(C[j]); else D[U[j]]=D[j],U[D[j]]=U[j],S[C[j]]++;//这里没写S[C[j]]--时也过了,想想确实不影响正确性 } if (dance()) return 1; for (int j=L[i]; j!=i; j=L[j]) { if (flag[j]==flag[i]) resume(C[j]); else U[D[j]]=j,D[U[j]]=j,S[C[j]]--; } } R[L[c]]=c; L[R[c]]=c;//恢复列指针c return 0; } int main() { int k,x; char str[5]; while (~scanf("%d%d",&n,&m)) { init(); for (int i=1; i<=n; i++) { scanf("%d",&k); while (k--) { scanf("%d%s",&x,&str); if (str[1]=='N') add_link(i,x,1); else add_link(i,x,0); } } if (!dance()) puts("-1"); } return 0; }