1024 (程序员节) 欢乐赛 T3 班服 (状压DP)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1024 (程序员节) 欢乐赛 T3 班服 (状压DP)相关的知识,希望对你有一定的参考价值。
题面:
班服
(shirt.pas/.c/.cpp)
时间限制:1s;内存限制 128MB
题目描述:
要开运动会了,神犇学校的n个班级要选班服,班服共有100种样式,编号1~100。现在每个班都挑出了一些样式待选,每个班最多有100个待选的样式。要求每个班最终选定一种样式作为班服,且该班的样式不能与其他班级的相同,求所有可能方案的总数,由于方案总数可能很大,所以要求输出mod 1000000007后的答案。
输入描述:
共有T组数据。
对于每组数据,第一行为一个整数n,表示有n个班级。
2~n+1行,每行有最多100个数字,表示第i-1班待选班服的编号。
输出描述:
对于每组数据,输出方案总数 mod 1000000007后的答案。
样例输入:
2
3
5 100 1
2
5 100
2
3 5
8 100
样例输出:
4
4
数据范围:
对于30%的数据,1<=T<=3, 1<=n<=3,每班待选样式不超过10种。
对于50%的数据,1<=T<=5, 1<=n<=5,每班待选样式不超过50种。
对于100%的数据,1<=T<=10, 1<=n<=10,每班待选样式不超过100种。
在考场上本蒟蒻根本没有想到DP,还以为是排列组合(考SM♂),结果没想出来,就只有一心打暴搜40分退群OTZ。
其实这道题还是很好想到用动态规划的,因为是求方案最大值,再看一眼数据范围和题意,就大致可以猜到是状态压缩DP。
思路:
(就是正常的DP思路啊……)每次枚举可能的服装种类,再枚举每个教室,确定该教室是否可以选择该服装,最后枚举每种状态是否可以选择,输出dp[100][1<<n]就好了。
这是转移方程:
dp[i][j]=(dp[i][j]+dp[i-1][j^(1<<(k-1))])%MOD;//i是第几种服装,j是第几种状态,k是第几间教室。
其他就没有什么了,具体的看代码吧:
#include<bits/stdc++.h> using namespace std; #define FOR(l,r,i) for(int i=l;i<=r;++i) const int N=110; const int MOD=1000000007; int f[N][1025],a[N][N],n,tn;//a[k][i]代表第k间教室,第i件服装,n是教室数,nt是状态数。 //f[i][j]代表前i件服装,第j种状态。 template<class T>inline void read(T &x)//读入优化。 { x=0;int f=0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){ f|=(ch==‘-‘); ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } x=f ? -x:x; return; } inline void init()//初始化 { scanf("%d",&n); memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); int i,x; char ch; for(i=1;i<=n;i++) while(scanf("%d%c",&x,&ch)) { a[i][x]=1; if(ch==‘\n‘) break; } tn=(1<<n)-1; //注意这里,如果不减一, 则在状态压缩的过程中会出现类似10000000……的数字,导致越界。 f[0][0]=1; return; } inline void Solve_DP() { FOR(1,100,i) { FOR(0,tn,j)//转移上一次的状态/ f[i][j]=f[i-1][j]; FOR(1,n,k) { if(!a[k][i])continue;//如果第k间教室没有这件服装,就排除它。 FOR(0,tn,j)if(j&(1<<(k-1)))//在该状态下需要第j间教室参与。 f[i][j]=(f[i][j]+f[i-1][j^(1<<(k-1))])%MOD;//此时的状态加上与取前i-1件服装时没有取第k间教室。 } } return; } int main() { freopen("shirt.in","r",stdin); freopen("shirt.out","w",stdout); int T,x,k=0; char ch; read(T); while(T--){ init(); Solve_DP(); printf("%d\n",f[100][tn]); } fclose(stdin); fclose(stdout); return 0; }
以上是关于1024 (程序员节) 欢乐赛 T3 班服 (状压DP)的主要内容,如果未能解决你的问题,请参考以下文章