【状态压缩DP】[2016"百度之星" - 初赛(Astar Round2A)]Sitting in Line

题目

Problem Description
度度熊是他同时代中最伟大的数学家,一切数字都要听命于他。现在,又到了度度熊和他的数字仆人们玩排排坐游戏的时候了。游戏的规则十分简单,参与游戏的N个整数将会做成一排,他们将通过不断交换自己的位置,最终达到所有相邻两数乘积的和最大的目的,参与游戏的数字有整数也有负数。度度熊为了在他的数字仆人面前展现他的权威,他规定某些数字只能在坐固定的位置上,没有被度度熊限制的数字则可以自由地交换位置。

Input
第一行一个整数T,表示T组数据。
每组测试数据将以如下格式从标准输入读入:

N

a1p1

a2p2

:

aNPN

第一行,整数 N(1≤N≤16),代表参与游戏的整数的个数。

从第二行到第 (N+1) 行,每行两个整数,ai(−10000≤ai≤10000)、pi(pi=−1 或 0≤pi

分析

这道题一开始看见数据这么小,搜索?16!太大了
还有一种解决NP问题的算法就是状态压缩DP了,再仔细看了一下题,感觉很像哈密顿路,只是规定了第pi个经过的点必须是i而已。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[1<<16][16];
int a[20],p[20],ans,T,rp[20],n,cnt[1<<16];
bool vis[20];
template<class T>
void Read(T &x){
    char c;
    bool f=0;
    while(c=getchar(),c!=EOF){
        if(c=='-')
            f=1;
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            if(f)
                x=-x;
            return;
        }
    }
}
int lowbit(int x){
    return x&-x;
}
void dp(){
    int s,t=1<<n,j,q;
    int i;
    if(vis[0])
        f[1<<rp[0]][rp[0]]=0;
    else
        for(i=0;i<n;i++)
            if(p[i]==-1)
                f[1<<i][i]=0;
    for(s=1;s<t;s++){
        cnt[s]=cnt[s^lowbit(s)]+1;
        if(vis[cnt[s]-1]){
            if(!(s&(1<<rp[cnt[s]-1])))
                continue;
            q=s^(1<<rp[cnt[s]-1]);
            for(i=0;i<n;i++)
                f[s][rp[cnt[s]-1]]=max(f[s][rp[cnt[s]-1]],f[q][i]+a[i]*a[rp[cnt[s]-1]]);
        }
        else
            for(i=0;i<n;i++)
                if(p[i]==-1&&(s&(1<<i)))
                    for(q=s^(1<<i),j=0;j<n;j++)
                        f[s][i]=max(f[s][i],f[q][j]+a[j]*a[i]);
    }
    for(i=0;i<n;i++)
        ans=max(ans,f[t-1][i]);
}
int main()
{
    Read(T);
    int cnt=0;
    while(T--){
        Read(n);
        int i;
        ans=0x80808080;
        memset(f,0xa0,sizeof f);
        memset(vis,0,sizeof vis);
        for(i=0;i<n;i++){
            Read(a[i]),Read(p[i]);
            if(~p[i])
                vis[p[i]]=1,rp[p[i]]=i;
        }
        if(n==1)
            ans=0;
        else        
            dp();
        printf("Case #%d:\n%d\n",++cnt,ans);
    }
}
posted @ 2016-05-21 21:41  outer_form  阅读(132)  评论(0编辑  收藏  举报