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

zoj3777(状态压缩)

时间:2015-09-03 23:08:33      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:

题目阐述:

给定n个座位,n个人,每个人可以做n个位置中的任意一个,P[i][j]代表第i个人做第j个位置获得的分数,求有多少种排列方式使得获得的分数大于等于M。

这道题跟数位dp的思想很像,都是穷举可能的方式,不过数位DP可以记忆化,这道题由于n较小,可以直接状态压缩.

定义状态d[i][s][t]代表已经放了i个座位,放的人数集合为s,获得分数为t的排列的数量。

然后每次暴力枚举每个位置可能会放的人

d[i][s | (1 << j)][t+ p[j][i]] +=d[i-1] [s] [t];

重点是如何实现:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define maxn 13
using namespace std;
int d[1<<(maxn)][505]; //表示到达状态s时产生的最大能量
int n,m;
int P[maxn][maxn];
int ans;
void init()
{
    ans=0;
    memset(d,0,sizeof(d));
}
//GCD
//求最大公约数
//O(logn)
int gcd(int a, int b)
{
    if (b == 0)
    return a;
    else
    return gcd(b, a%b);
}
int isok(int i)
{
    int t=0;
    while(i)
    {
        if(i&1) t++;
        i>>=1;
    }
    return t;
}
void solve()
{
    int tot=(1<<n)-1;
     d[0][0]=1; //其实可以理解成d[-1][0][0],否则下面就需要特殊处理i等于0
    for(int i=0;i<n;i++)   //代表第i个位置
     {
         for(int s=0;s<=tot;s++)  //遍历所有状态
            {
                    if(isok(s)!=i)   continue ;//检测哪些是前i-1个位置的状态
                    for(int t=0;t<=m;t++)  //遍历所有获得的分数
                    {
                       if(!d[s][t])  continue; //检测哪些是前i-1个位置获得的分数
                      for(int j=0;j<n;j++)  //枚举第i个位置可能放的人
                     {
                         if( s & (1<<j) ) //检测前i-1个位置是否放过
                            continue;
                         int state= s | (1<<j);
                         int MM=min(m,t+P[j][i]);
                         d[state][MM]+=d[s][t];
                     }
                    }
            }
     }
     ans=d[tot][m];
}

int main()
{
   // freopen("test.txt","r",stdin);
    int fac[maxn];
    fac[0]=1;
    for(int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
           scanf("%d",&P[i][j]);
        }
        solve();
        int d = gcd(fac[n], ans);
        if (ans == 0)
            printf("No solution\n");
        else
            printf("%d/%d\n", fac[n]/d, ans/d);
    }
    return 0;
}

bfs实现:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#define maxn 13
using namespace std;
int d[1<<(maxn)][505]; //表示到达状态s时产生的最大能量
int n,m;
int P[maxn][maxn];
int ans;
int gcd(int a, int b)
{
    if (b == 0)
    return a;
    else
    return gcd(b, a%b);
}

int bit(int i)
{
    int t=0;
    while(i)
    {
        if(i&1) t++;
        i>>=1;
    }
    return t;
}
struct node
{
    int s,t,cnt=0;
};
int  visit[1<<maxn][505];
void   bfs()
{
     queue  < node > que;
     memset(visit,0,sizeof(visit));
     int tot=(1<<n)-1;
     node start,last;
     start.s=0; start.t=0;
     start.cnt=0;
     que.push(start);
     visit[start.s][start.t]=1;
     d[0][0]=1;
     while(!que.empty())
     {
         node cur=que.front();
         que.pop();
         for(int i=0;i<n;i++)
         {
             if(cur.s & (1<<i))
                continue;
             node next  ;
             next.s= cur.s | (1<<i);
             next.cnt=cur.cnt+1;
             next.t= min(m,cur.t+P[i][cur.cnt]); //将第i个人放在当前位置,然后才会加1
             d[next.s][next.t] += d[cur.s][cur.t];
             if(visit[next.s][next.t])  //保证只进队一次
                continue;
             que.push(next);
             visit[next.s][next.t]=1;
         }
     }
     ans=d[tot][m];
}

int main()
{
  // freopen("test.txt","r",stdin);
    int fac[maxn];
    fac[0]=1;
    for(int i=1;i<maxn;i++)
        fac[i]=fac[i-1]*i;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
         ans=0;
         memset(d,0,sizeof(d));;
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
           scanf("%d",&P[i][j]);
        }
        bfs();
        int d = gcd(fac[n], ans);
        if (ans == 0)
            printf("No solution\n");
        else
            printf("%d/%d\n", fac[n]/d, ans/d);
    }
    return 0;
}

 

zoj3777(状态压缩)

标签:

原文地址:http://www.cnblogs.com/xianbin7/p/4780565.html

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