codeforces 107C Arrangement (状压dp)

题意:

给出n个人和n个座位,给出m对限制,每对限制要求ai这个人的座位要排在bi这个人的前面。现在要求满足条件的第y-2001大的字典序的座位排列。

题解:
题目挺好的,处理方法很特别。对于这样的题目,我们首先想想暴力,那就是枚举从1开始的各种满足条件的序列,其实在枚举的时候我们可以这样优化,首先枚举第一个作为排的人,然后以排好的人为基准,往下继续排计算出对应的排列数,如果排列数大于想在的y,那么这位排的人是合法的,如果小于则y减去得到的排列数。排第二位的人,重复刚才的操作。

对于排列数的计算可以用dp,状压dp在O(2^n)算出来,时间完全够。


#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define B(x) (1<<(x))
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const ll MOD=10007;
const int maxn=100000+5;
ll dp[B(16)+6];///表示在某个i之前的位子确定人后,状态为s时排列的个数
int ans[20],g[20],mark[20],full;

int main()
{
    int n,m,a,b,f;
    ll y;
    while(scanf("%d %I64d %d",&n,&y,&m)!=EOF)
    {
        memset(g,0,sizeof g);
        memset(ans,-1,sizeof ans);
        memset(mark,0,sizeof mark);
        for(int i=0;i=n) { f=0; puts("The times have changed"); break; }
                memset(dp,0,sizeof dp);
                dp[0]=1;
                for(int s=0;s<=full;s++)
                if(dp[s])
                {
                    int cnt=__builtin_popcount(s);
                    for(int k=0;k=dp[full])
                    y-=dp[full];
                else
                {
                    mark[ans[i]]=1;
                    break;
                }
            }
        }
        if(!f)continue;
        for(int i=0;i



你可能感兴趣的:(动态规划—状压dp,codeforces,动态规划)