HDU 5045 状压DP 上海网赛

比赛的时候想的是把n个n个的题目进行状压 但这样不能讲究顺序,当时精神面貌也不好,真是挫死了

其实此题的另一个角度就是一个n个数的排列,如果我对n个人进行状压,外面套一个按题目循序渐进的大循环,那么,在当前做第i个题目,前i-1个题目已经做完,然后做完的人的状态为j, j可能是1110 1101 1011什么的(假设已经做了三道题),因为我这样就可以只管状态而不管顺序了,我只取这种状态下的最大值,他究竟是怎么个顺序排列我不用管

到此。。。好像问题就没有什么问题了,这种做法重复 m/n次最后把剩余的再跑一下就可以了,因为每次考虑第i个题的时候 只和i-1有关,则用个滚动数组即可,比较麻烦的是每次要清空,只能说空间和时间不可兼得啊

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
double A[11][1010];
int n,m;
double dp[2][1<<11];
int main()
{
    int t,kase=0;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++){
            for (int j=0;j<m;j++) scanf("%lf",&A[i][j]);
        }
        int ALL=1<<n;
        for (int i=0;i<=ALL;i++){
            dp[0][i]=dp[1][i]=0;
        }
        for (int i=0;i<n;i++){
            dp[0][1<<i]=A[i][0];
        }
        int p=0;
        double ans=0;
        for (int i=1;i<m;i++){
            p^=1;
            for (int j=0;j<=ALL;j++) dp[p][j]=0;
            for (int j=0;j<ALL;j++){
                if (dp[p^1][j]==0) continue;
                for (int k=0;k<n;k++){
                    if ((1<<k)&j) continue;
                    int nt=(1<<k)|j;
                    if (nt==ALL-1) nt=0;
                    dp[p][nt]=max(dp[p][nt],dp[p^1][j]+A[k][i]);
                    if (i==m-1) ans=max(ans,dp[p][nt]);
                }
            }
        }

        printf("Case #%d: %.5lf\n",++kase,ans);
    }
}

 

posted @ 2014-09-29 23:18  KRisen  阅读(289)  评论(0编辑  收藏  举报