UVA 6625(状态压缩dp)

这个题目的意思是给定k,n( k,n<=7)

并给定k行每行有几个连续的空格,所有的行左对齐,每一行最多7个,下面的行的空格数<=上面相邻行的空格数

给定一个填数字的规则,当对于任意位置i,j ,  num[ i ][ j ] > num[ i-1 ][ j ] && num[ i ][ j ] >= num[ i ][ j-1 ] 问有(只用数字1->n)有多少种填满空格的方案。

解:

对于直接定义前每一行被填成了什么数,当前走到了第几行,这样的状态状态总数为7*7^7,状态转移为sum(7 - numi),空间时间都受不了。

那么,对于本题目还有一个性质,对于任意的一列其数值成增长趋势,那么所有列的状态最多不超过 2^7(可以想一想为什么)

那么定义d[ i ][ s ]代表走到第i列,前一列的状态是s( s为二进制数最大为(1<<7)-1 , 对于任意位置该位置为1 代表选了i, 0代表没选,1的个数即和该列空格数相同)

那么状态转移就很明显了,不多说了,可以按1的个数,将2^n个状态分到不同数组里,来优化状态转移。

每个状态的最大转移为 c(7,3) = 7*6*5/3/2= 35;

最大代价一定比 (7 * 2^7 * 35 = 31360) 小

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <list>
#include <cstdlib>
#include <queue>
#include <stack>
#include <cmath>
#define ALL(a) a.begin(), a.end()
#define clr(a, x) memset(a, x, sizeof a)
#define fst first
#define snd second
#define pb push_back
#define ls (rt<<1)
#define rs (ls|1)
#define lson l, mid, ls
#define rson mid+1, r, rs
#define rep(i,n) for(int i=0;i<(int)n;i++)
#define rep1(i,x,y) for(int i=x;i<=(int)y;i++)
#define sqr(x) ((x)*(x))
using namespace std;
typedef long long LL;
typedef long long ll;
typedef pair<int, int> pii;

const int N = 10;
const int M = 1<<7;
int bitcount(int x)
{
    return (x==0 ? 0:bitcount(x/2)+(x&1));
}
vector<int> G[N];
int a[N],l[N],k,n;
void init()
{
    for(int i=1; i<N; i++) G[i].clear();
    int lim = (1<<n);
    for(int i=1; i<lim; i++)
    {
        G[bitcount(i)].push_back(i);
    }
    G[0].clear();
    G[0].push_back(0);
    for(int i=1; i<=a[1]; i++)
    {
        l[i] = 0;
        for(int j=1; j<=k && a[j]>=i; j++)
            l[i]++;
    }
}
int c1[N],c2[N],t1,t2;
inline int judge(int s,int ps)
{
    t1 = 0, t2 = 0;
    for(int i=0; i<n; i++) if(s&(1<<i)) c1[++t1]=i;
    for(int i=0; i<n; i++) if(ps&(1<<i)) c2[++t2]=i;
    for(int i=1; i<=t2; i++) if(c2[i]<c1[i]) return 0;
    return 1;
}
ll d[N][M];
int main()
{
    while(scanf("%d",&k)==1)
    {
        for(int i=1; i<=k; i++)
        {
            scanf("%d",&a[i]);
        }
        scanf("%d",&n);
        init();
        int tn=a[1];
        l[0]=0;
        for(int i=tn+1; i>=1; i--)
        {
            int p = l[i-1];
            for(int j=0; j<G[p].size(); j++)
            {
                if(i == tn+1)
                {
                    d[i][G[p][j]] = 1;
                    continue;
                }
                d[i][G[p][j]] = 0;
                if(i==1)
                {
                    for(int q = 0; q<G[l[i]].size(); q++)
                        d[i][G[p][j]]=d[i][G[p][j]]+d[i+1][G[l[i]][q]];
                }
                else
                {
                    for(int q = 0; q<G[l[i]].size(); q++) if(judge(G[p][j],G[l[i]][q]))
                        {
                            d[i][G[p][j]]=d[i][G[p][j]]+d[i+1][G[l[i]][q]];
                        }
                }
            }
        }
        printf("%lld\n",d[1][0]);
    }
    return 0;
}



,

你可能感兴趣的:(Algorithm,C++,uva)