hdu4979 A simple math problem.Dancing Links,打表
来源:互联网 发布:mmd虎视眈眈镜头数据 编辑:程序博客网 时间:2024/05/21 17:50
hdu4979 A simple math problem.
题意是,给你n、m、r,问1..n中选m个数的集合至少要选多少个,才能包含所有1..n中选r个数的集合。(不重复)
题解说这个题目没有多项式解法。只能用搜索。然后建议了Dancing links。
然后标程就给了一个表有木有!
这种题你也敢出出来,逗我呢啊。
然后我还是试了下DLX的解法。
先回顾一下DLX:
首先我们构造一个01矩阵g[n][m]。如果说g[i][j]==1,就叫i行覆盖了j列。
DLX的两种经典问题:
1.精确覆盖问题:取某些行,这些行覆盖所有的列,且每个列都有且只有一个1。
2.重复覆盖问题:取某些行,这些行覆盖所有的列。一般来说这样的问题要求行数的最小值。
对于本题:
先建立所有的取m和取r的集合,如果某个取m集合能包含取r的集合,那么就在关系矩阵上的该位置为1.
例如,n=2,m=1,r=1.取m个的集合有两种{1}、{2},取r个集合也是两种{1}、{2}。
那么关系矩阵g就是
1 0
0 1
每行代表某个取m的集合能包含哪些某个取r的集合。
那么本题的目标就是求最小的行数量,使得所有列都被至少一行覆盖。这是一个重复覆盖问题。
然后枚举所有的n,m,r,因为他们都很小,所以打表就可以愉快地AC了。
我的程序在我的电脑上运行了5分钟。
题意是,给你n、m、r,问1..n中选m个数的集合至少要选多少个,才能包含所有1..n中选r个数的集合。(不重复)
题解说这个题目没有多项式解法。只能用搜索。然后建议了Dancing links。
然后标程就给了一个表有木有!
这种题你也敢出出来,逗我呢啊。
然后我还是试了下DLX的解法。
先回顾一下DLX:
首先我们构造一个01矩阵g[n][m]。如果说g[i][j]==1,就叫i行覆盖了j列。
DLX的两种经典问题:
1.精确覆盖问题:取某些行,这些行覆盖所有的列,且每个列都有且只有一个1。
2.重复覆盖问题:取某些行,这些行覆盖所有的列。一般来说这样的问题要求行数的最小值。
对于本题:
先建立所有的取m和取r的集合,如果某个取m集合能包含取r的集合,那么就在关系矩阵上的该位置为1.
例如,n=2,m=1,r=1.取m个的集合有两种{1}、{2},取r个集合也是两种{1}、{2}。
那么关系矩阵g就是
1 0
0 1
每行代表某个取m的集合能包含哪些某个取r的集合。
那么本题的目标就是求最小的行数量,使得所有列都被至少一行覆盖。这是一个重复覆盖问题。
然后枚举所有的n,m,r,因为他们都很小,所以打表就可以愉快地AC了。
我的程序在我的电脑上运行了5分钟。
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define NN 75#define MM 75#define INF 101000int g[NN][MM],tg[NN][MM];int R[NN*MM],L[NN*MM],U[NN*MM],D[NN*MM],C[NN*MM],S[MM],cnt[MM];int head,td;int ans[10][10][10];void remove(int c){//仅删除列 for(int i=D[c];i!=c;i=D[i]){ R[L[i]]=R[i];L[R[i]]=L[i]; }}void resume(int c){//恢复列 for(int i=U[c];i!=c;i=U[i]){ R[L[i]]=i;L[R[i]]=i; }}bool has[NN];int hash(){ int ret=0,i,j,c,last; memset(has,0,sizeof(has)); for(c=R[head];c!=head;c=R[c]){ if (!has[c]){ has[c]=1; ret++; for(i=D[c];i!=c;i=D[i]) for (j=R[i];j!=i;j=R[j]){ //printf("hasc=%d %d %d\n",j,i,c); has[C[j]]=1; } } } //printf("has=%d\n",ret); return ret;}void dfs(int nans,int &ans){ if (nans+hash()>=ans) return; if (R[head]==head) {if (nans<ans) ans=nans; return;}//找到一组解,列头链表为空 //对于不必消去所有列的题目,不必消去的列放在后面,R[head]>xx||R[head]==head则找到解 int i,j=INF,c; for(i=R[head];i!=head;i=R[i]){//找总数最小的一个列,不必消去所有列的题目i<=xx if (S[i]<j) {j=S[i];c=i;} } if (j==0) return;//无法找到覆盖行,无解返回 for(i=D[c];i!=c;i=D[i]){ //枚举用哪行覆盖该列 remove(i); for(j=R[i];j!=i;j=R[j]) remove(j);//删除该行为1的列 dfs(nans+1,ans); for(j=L[i];j!=i;j=L[j]) resume(j);//回溯恢复 resume(i); }}int DLX(int n,int m){ head=td=0; int last=head,i,j,tt,fi; for(i=1;i<=m;++i){ cnt[i]=0; for(j=1;j<=n;++j)if (g[j][i]) cnt[i]++; } for(i=1;i<=m;i++){//建立列头链表 R[last]=++td;L[td]=last;U[td]=D[td]=td;C[td]=i;S[td]=cnt[i];last=td; } R[last]=head;L[head]=last; for(i=1;i<=n;i++) for(j=1;j<=m;j++) if (g[i][j]) tg[i][j]=++td; else tg[i][j]=0; //结点映射/* for(i=1;i<=n;++i){ for(j=1;j<=m;++j){ printf("%d %d ",g[i][j],tg[i][j]); } printf("\n"); } */ //printf("td=%d\n",td); for(j=1;j<=m;j++){//建立上下链表 last=j; for(i=1;i<=n;i++)if (tg[i][j]){ tt=tg[i][j]; D[last]=tt;U[tt]=last;C[tt]=j;//建立上下链表时维护D,U,C last=tt; } D[last]=j;U[j]=last; } for(i=1;i<=n;i++){//左右链表 for(j=1;j<=m;j++)if (tg[i][j]){ last=fi=tg[i][j]; for(;j<=m;j++)if (tg[i][j]){ tt=tg[i][j]; R[last]=tt;L[tt]=last;//L,R //printf("cacaca %d %d %d\n",tt,R[last],L[tt]); last=tt; } R[last]=fi;L[fi]=last; } } int ans=m;//本题最差结果是列的数量 dfs(0,ans); return ans;}int ex[10];int st1[NN][10],st2[NN][10],sv[10];bool contain(int a,int m,int b,int r){ int i; for(i=1;i<=8;++i) ex[i]=0; for(i=1;i<=m;++i) ex[st1[a][i]]=1; for(i=1;i<=r;++i) if (ex[st2[b][i]]==0) return false; return true;}void getnum(int st[NN][10],int now,int m,int n,int step,int &totn){ int i; if (now!=m&&step>n) return; if (now==m){ totn++; for(i=1;i<=m;++i){ st[totn][i]=sv[i]; } return; } for(i=step;i<=n;++i){ sv[now+1]=i; getnum(st,now+1,m,n,i+1,totn); }}int makeset(int st[NN][10],int n,int m){ int totn=0; getnum(st,0,m,n,1,totn); return totn;}void make_graph(int n,int m,int r){ int i,j; int sn1=makeset(st1,n,m); int sn2=makeset(st2,n,r); //printf(" %d %d %d %d %d\n",n,m,r,sn1,sn2); for(i=1;i<=sn1;++i){ for(j=1;j<=sn2;++j){ if (contain(i,m,j,r)) g[i][j]=1; else g[i][j]=0; } } ans[n][m][r]=DLX(sn1,sn2);}void output(){ int i,j,k; printf("{\n"); for(i=1;i<=8;++i){ printf(" {\n"); for(j=1;j<=8;++j){ printf(" {"); for(k=1;k<=8;++k){ printf(" % 2d",ans[i][j][k]); if (k!=8) printf(","); } printf("}"); if (j!=8) printf(","); printf("\n"); } printf(" }"); if (i!=8) printf(","); printf("\n"); } printf("};\n");}int ans2[10][10][10]={ { { 1, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 2, 0, 0, 0, 0, 0, 0, 0}, { 1, 1, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 3, 0, 0, 0, 0, 0, 0, 0}, { 2, 3, 0, 0, 0, 0, 0, 0}, { 1, 1, 1, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 4, 0, 0, 0, 0, 0, 0, 0}, { 2, 6, 0, 0, 0, 0, 0, 0}, { 2, 3, 4, 0, 0, 0, 0, 0}, { 1, 1, 1, 1, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 5, 0, 0, 0, 0, 0, 0, 0}, { 3, 10, 0, 0, 0, 0, 0, 0}, { 2, 4, 10, 0, 0, 0, 0, 0}, { 2, 3, 4, 5, 0, 0, 0, 0}, { 1, 1, 1, 1, 1, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 6, 0, 0, 0, 0, 0, 0, 0}, { 3, 15, 0, 0, 0, 0, 0, 0}, { 2, 6, 20, 0, 0, 0, 0, 0}, { 2, 3, 6, 15, 0, 0, 0, 0}, { 2, 3, 4, 5, 6, 0, 0, 0}, { 1, 1, 1, 1, 1, 1, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 7, 0, 0, 0, 0, 0, 0, 0}, { 4, 21, 0, 0, 0, 0, 0, 0}, { 3, 7, 35, 0, 0, 0, 0, 0}, { 2, 5, 12, 35, 0, 0, 0, 0}, { 2, 3, 5, 9, 21, 0, 0, 0}, { 2, 3, 4, 5, 6, 7, 0, 0}, { 1, 1, 1, 1, 1, 1, 1, 0}, { 0, 0, 0, 0, 0, 0, 0, 0} }, { { 8, 0, 0, 0, 0, 0, 0, 0}, { 4, 28, 0, 0, 0, 0, 0, 0}, { 3, 11, 56, 0, 0, 0, 0, 0}, { 2, 6, 14, 70, 0, 0, 0, 0}, { 2, 4, 8, 20, 56, 0, 0, 0}, { 2, 3, 4, 7, 12, 28, 0, 0}, { 2, 3, 4, 5, 6, 7, 8, 0}, { 1, 1, 1, 1, 1, 1, 1, 1} }};int main(){ /* freopen("4979out.txt","w",stdout); int i,j,k; memset(ans,0,sizeof(ans)); for(i=1;i<=8;++i){ for(j=1;j<=i;++j){ for(k=1;k<=j;++k){ make_graph(i,j,k); printf("%d %d %d %d ",i,j,k,ans[i][j][k]); } printf("\n"); } printf("\n"); } output(); */ int t,cas,n,m,r; scanf("%d",&t); cas=0; while(t--){ scanf("%d%d%d",&n,&m,&r); printf("Case #%d: %d\n",++cas,ans2[n-1][m-1][r-1]); } return 0;}
0 0
- hdu4979 A simple math problem.Dancing Links,打表
- hdu4979 A simple math problem.
- HDU4979 A simple math problem.
- HDU4979-A simple math problem.
- A Simple Math Problem
- A Simple Math Problem
- A Simple Math Problem
- A Simple Math Problem
- A Simple Math Problem
- A simple math problem
- A Simple Math Problem
- hdu 4979 A simple math problem. DLX(多重覆盖)+打表
- hdu - 4979 - A simple math problem.(可重复覆盖DLX + 打表)
- A Simple Math Problem hdu1757
- hdu A Simple Math Problem
- hdu1757 A Simple Math Problem
- HDU1757 A Simple Math Problem
- HDU1757 A Simple Math Problem
- Trie字典树【模板
- R语言
- Android之XML文件解析
- mongodb 使用场景和不使用场景
- Lession 30 输入输出流
- hdu4979 A simple math problem.Dancing Links,打表
- AC自动机 病毒侵袭 hdu2896
- 正则表达式
- linux文件操作总结
- 家纺网数据表分析
- 图像信息熵matlab代码
- Codeforces 258B. Little Elephant and Elections【数位DP,DFS】
- 前端交互效果注意
- HDU 1541 Stars (线段树)