一、.算法参考资料:
东西太多,讲不清楚。翻译过来的论文,momodi的论文以经很不错了!就直接贴链接了。
1.dancing links(跳舞链)参考资料:http://sqybi.com/
点里面的works链接里有dlx资料的压缩包
2.momodi的论文:http://gaoyunxiang.com/wp-content/uploads/2010/02/Dancing_Links.pdf
3.2011阿里巴巴程序设计公开赛解题报告:http://www.notonlysuccess.com/?p=1062
最好是先自己把这个算法写出来,然后去对比模板,这样就能发现效率的所在
二、代码(最好不要看,仅仅是为了备份用,写得又长又不好懂!)
不过用了点小小的tricky——prepare(),结果跑到了78MS,哈哈!
#include <iostream> #include<cstdio> #include<algorithm> #include<vector> #include<string> //freopen("data.in","r",stdin); using namespace std; #define MAXN 1000// struct Node { int x,y; int l,r,u,d; int s; Node(int ll,int rr,int uu,int dd,int xx,int yy){l=ll;r=rr;u=uu;d=dd;s=0;x=xx;y=yy;} }; struct Table { int h;//头结点 vector<Node> v; //i:(i<<1,(i+n)<<1)//第i个人的行和列头结点的第一模式索引 //bool f[N+1];//标记第i个人是否有2种模式 //最后发现是没必要的建图时可以在图中体现这种关系 int n;//人数 int low,high; bool vis[MAXN]; //注意x结点的特殊性 inline void delC(int x) { for(int i=v[x].d;i!=x;i=v[i].d) { v[v[i].l].r=v[i].r; v[v[i].r].l=v[i].l; } } inline void linkC(int x) { for(int i=v[x].u;i!=x;i=v[i].u) { v[v[i].r].l=i; v[v[i].l].r=i; } } inline void delR(int x) { for(int i=v[x].r;i!=x;i=v[i].r) { v[v[i].u].d=v[i].d; v[v[i].d].u=v[i].u; v[v[i].y].s--; } } inline void linkR(int x) { for(int i=v[x].l;i!=x;i=v[i].l) { v[v[i].u].d=i; v[v[i].d].u=i; v[v[i].y].s++; } } //cover //1.覆盖x所在列 //2.覆盖<x1,x2,……>xi所在列 //3.删除另外一个模式的行(有) //十字链表结构还存在 inline void cover(int x) { delC(x); for(int i=v[x].r;i!=x;i=v[i].r)if(!v[i].s)delC(i); if(v[v[x].y^1].s)delR(v[x].x^1);//存在另外一种模式 } //resume //1.删除另外一个模式的行(有) //2.恢复<x1,x2,……>xi所在列 //3.恢复x所在列 inline void resume(int x) { if(v[v[x].y^1].s)linkR(v[x].x^1); for(int i=v[x].l;i!=x;i=v[i].l)if(!v[i].s)linkC(i); linkC(x); } void init() { v.clear(); //创建表头,断开结点 h=1; int i; for(i=0;i<=(n<<1|1);i++)v.push_back(Node(i,i,i,i,i,1));//2*n+2 for(i=(n<<1)+2;i<(n<<2|2);i++)v.push_back(Node(i,i,i,i,0,i));//4*n+2 } void linkHeader(int x,int y) { v[x].y=h; v[x].u=v[h].u;v[x].d=h;v[v[h].u].d=x;v[h].u=x; v[y].l=v[h].l;v[y].r=h;v[v[h].l].r=y;v[h].l=y; v[h].s++;//对所有的列统计个数,包括头结点 } void add(int x,int y) { v.push_back(Node(v[x].l,x,v[y].u,y,x,y)); int cnt=v.size()-1;//注意cnt在push_back里先加了 v[v[x].l].r=cnt;v[x].l=cnt;v[x].s++;//用来判断是否是行头结点 v[v[y].u].d=cnt;v[y].u=cnt;v[y].s++; } void build() { for(int i=1;i<=n;i++) { int m; scanf("%d",&m); int x1=i<<1,y1=(i+n)<<1;// linkHeader(x1,y1); add(x1,y1);//!! if(m==2) { int x2=x1|1,y2=y1|1; linkHeader(x2,y2); add(x1,y2);//!!0模式打败自己的两种模式 add(x2,y1); add(x2,y2); } for(int j=0;j<m;j++) { int num,obj,model; scanf("%d",&num); for(int k=0;k<num;k++) { scanf("%d%d",&obj,&model); y1=( (obj+1+n)<<1 )|model; add(x1|j,y1);//第x1个人的第j种状态打败第obj+1人的model状态 } } } } int H() { memset(vis,0,sizeof(vis)); int ret=0; for(int y=v[h].r;y!=h;y=v[y].r) { if(!vis[y]) { ret++;vis[y]=true; for(int x=v[y].d;x!=y;x=v[x].d) { for(int z=v[x].r;z!=x;z=v[z].r) vis[v[z].y]=true; } } } return ret; } bool dfs(int step,int cur) { if(step+H()>cur)return false; if(v[h].r==h)return true; int ms=v[v[h].r].s,my=v[h].r; for(int y=v[h].r;y!=h;y=v[y].r)//选出最少的一列 { if(ms>v[y].s) { ms=v[y].s; my=y; } } for(int x=v[my].d;x!=my;x=v[x].d) //my是列头 { cover(x); if(dfs(step+1,cur)) { resume(x); return true; } resume(x); } return false; } bool prepare() { low=0;high=n; int pre=v[h].r,cur; for(cur=v[v[h].r].r;cur!=h;cur=v[cur].r) { bool c=( ((pre^1)!=cur)||((pre^1)==cur&&v[pre].s>2) ); if(c&&v[cur].s==2)low++; pre=cur; } if(low==0)low=1; else high=n-1; int defeat=1;// for(int x=v[h].d;x!=h;x=v[x].d) { int tmp=0; int y1=v[v[x].r].y; bool first=true; for(cur=v[v[x].r].r;cur!=x;cur=v[cur].r) { int y2=v[cur].y; bool c1=y2==(y1^1); bool c2=!c1&&v[y2^1].s==0; if(c1&&c2)tmp++;// if((y2&1)&&(!c1)&&v[y2^1].s>2&&first) {//两种模式,并且另一种也能被打败 first=false; tmp++; } y1=y2; } if(tmp>defeat)defeat=tmp; } int must=n-defeat+1; if(high>must)high=must; if(low==high)return true; return false; } int dlx() { scanf("%d",&n); init(); build(); // output(v.size()); if(prepare())return low; // low=1;high=n; while(low<high) { int mid=(low+high)>>1; if(dfs(0,mid))high=mid; else low=mid+1; } return low; } void output(int cnt) { for(int i=1;i<cnt;i++) { //printf("%d %d %d %d\n",i,v[i].x,v[i].y,v[i].s); printf("%d %d %d %d %d\n",i,v[i].l,v[i].r,v[i].u,v[i].d); } cout<<endl; } }G; int main() { // freopen("data.in","r",stdin); int T; cin>>T; int cases=1; while(T--) { printf("Case %d: %d\n",cases++,G.dlx()); } return 0; }