码迷,mamicode.com
首页 > 其他好文 > 详细

1024 (程序员节) 欢乐赛 T3 班服 (状压DP)

时间:2017-10-24 23:02:25      阅读:368      评论:0      收藏:0      [点我收藏+]

标签:hellip   cpp   log   不能   turn   fclose   void   时间   etc   

题面:

班服

 (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)

标签:hellip   cpp   log   不能   turn   fclose   void   时间   etc   

原文地址:http://www.cnblogs.com/Wujiga/p/7725106.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!