题意:
有一种彩票,共有n个数字,其中r个为获奖数字,每次买彩票选择m个不同数字,若m个数字中包含r个获奖数字则获奖。问至少要买多少彩票彩能保证获奖,也就是说至少买多少次才彩票就能包含完所有的C(n,r)种情况。其中n>=m>=r。举例:n=6,m=3,r=2。只用买6张彩票即可。{1,2,3},{1,4,5},{1,3,6},{2,4,6},{2,5,6},{3,4,5}。
分析:
很明显就能发现,这是一个很裸的DLX。
n个 选 r 个,共有 C[n][r] 种选法,每种选法需要被覆盖,对应于 DLX 中的列。
n个 选 m 个,共有 C[n][m] 种选法,每种选法对应于 DLX 中的行。
但要注意的是直接跑太慢。
打表出来就好了。
打表代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
const int maxm=1005;
const int maxnode=maxn*maxm;
const int inf=0x3f3f3f3f;
struct DLX{
int n,m,size;
int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode];
int H[maxn],S[maxm];
int ansd,ans[maxn];
void init(int _n,int _m){
n=_n;
m=_m;
for(int i=0;i<=m;i++){
S[i]=0;
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R[m]=0;L[0]=m;
size=m;
for(int i=1;i<=n;i++){
H[i]=-1;
}
}
void Link(int r,int c){
++S[Col[++size]=c];
Row[size]=r;
D[size]=D[c];
U[D[c]]=size;
U[size]=c;
D[c]=size;
if(H[r]<0) H[r]=L[size]=R[size]=size;
else{
R[size]=R[H[r]];
L[R[H[r]]]=size;
L[size]=H[r];
R[H[r]]=size;
}
}
void remove(int c){
for(int i=D[c];i!=c;i=D[i]){
L[R[i]]=L[i];
R[L[i]]=R[i];
}
}
void resume(int c){
for(int i=U[c];i!=c;i=U[i]){
L[R[i]]=R[L[i]]=i;
}
}
bool v[maxm];
int f(){
int ret=0;
for(int c=R[0];c!=0;c=R[c]) v[c]=1;
for(int c=R[0];c!=0;c=R[c]){
if(v[c]){
ret++;
v[c]=false;
for(int i=D[c];i!=c;i=D[i]){
for(int j=R[i];j!=i;j=R[j]){
v[Col[j]]=false;
}
}
}
}
return ret;
}
void dance(int d){
if(d+f()>=ansd) return ;
if(R[0]==0){
if(d<ansd) ansd=d;
return ;
}
int c=R[0];
for(int i=R[0];i!=0;i=R[i]){
if(S[i]<S[c]){
c=i;
}
}
for(int i=D[c];i!=c;i=D[i]){
remove(i);
for(int j=R[i];j!=i;j=R[j]) remove(j);
dance(d+1);
for(int j=L[i];j!=i;j=L[j]) resume(j);
resume(i);
}
}
}dlx;
int bitcnt[(1<<8)+10];
int c[(1<<8)+10][(1<<8)+10];
int Bitcnt(int x){
int cnt=0;
while(x){
if(x&1) cnt++;
x>>=1;
}
return cnt;
}
void init(){
for(int i=0;i<(1<<8);i++){
bitcnt[i]=Bitcnt(i);
}
for(int i=1;i<=8;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
}
int col[(1<<8)+10];
void solve(int n,int m,int r){
int ccnt=0;
for(int i=1;i<(1<<n);i++){
if(bitcnt[i]==r){
col[i]=++ccnt;
}
}
int rcnt=0;
dlx.init(c[n][m],c[n][r]);
for(int i=1;i<(1<<n);i++){
if(bitcnt[i]==m){
rcnt++;
for(int j=i;j>0;j=(i&(j-1))){
if(bitcnt[j]==r){
dlx.Link(rcnt,col[j]);
}
}
}
}
dlx.ansd=inf;
dlx.dance(0);
printf("%d",dlx.ansd);
}
int main(){
init();
printf("{\n");
for(int n=1;n<=8;n++){
printf(" {\n");
for(int m=1;m<=n;m++){
printf(" {");
for(int r=1;r<=m;r++){
if(r>1) printf(",");
solve(n,m,r);
}
printf("}");
if(m==n) printf("\n");
else printf(",");
}
printf(" }");
if(n==8) printf("\n");
else printf(",\n");
}
printf("}\n");
return 0;
}
AC代码:
#include<bits/stdc++.h>
using namespace std;
int ans[10][10][10]=
{
{
{1}
},
{
{2}, {1,1}
},
{
{3}, {2,3}, {1,1,1}
},
{
{4}, {2,6}, {2,3,4}, {1,1,1,1}
},
{
{5}, {3,10}, {2,4,10}, {2,3,4,5}, {1,1,1,1,1}
},
{
{6}, {3,15}, {2,6,20}, {2,3,6,15}, {2,3,4,5,6}, {1,1,1,1,1,1}
},
{
{7}, {4,21}, {3,7,35}, {2,5,12,35}, {2,3,5,9,21}, {2,3,4,5,6,7}, {1,1,1,1,1,1,1}
},
{
{8}, {4,28}, {3,11,56}, {2,6,14,70}, {2,4,8,20,56}, {2,3,4,7,12,28}, {2,3,4,5,6,7,8}, {1,1,1,1,1,1,1,1}
}
};
int main(){
int T;
scanf("%d",&T);
for(int cs=1;cs<=T;cs++){
int n,m,r;
scanf("%d%d%d",&n,&m,&r);
printf("Case #%d: %d\n",cs,ans[n-1][m-1][r-1]);
}
return 0;
}