hdu 1074动态压缩

这题我一直以为是贪心做的,做了好久找不到规律

看了解题报告,学习了压缩dp,类似dist,{v(i)}=min{v(i)-k},这种NP问题,O(n*2^n),数据给的比较小,其实也只能给15了,直接用2<<15数组表示状态

每个状态,记录最优的pre,now,当然pre(上一个状态量)和now(当前节点值)是有关的,其实可以记录一个,最后递归输出now,有几个重要的过程注释在代码里了

哎,最坑的是,解题报告看那什么,直接记住代码了,最后还记错了=.=,不过还好,debug的时候,算是更加了解过程了,不说了,这周可以恶刷dist了,其实koubin的算法更加类似dist,这个代码和之前的dp接近

//状态压缩,用1111表示4中的取值情况,0000表示都不取,0001表示只取1
//这里dp判断还是比较简单的,类似最短路径的,{V{i}} = min{V{i}-k}(k属于i中的集合)
//这里路径小于0,这条路径损失的分数小于0,作0处理
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <string>

using namespace std;
const int MAXN = (1<<31)-1;
typedef struct{
    string cn;
    int tm;
    int del;
}course;
typedef struct{
    int pre;
    int now;
    int tm;
    int red;
}node;
course a[16];
node dp[1<<15];

void init(){
    dp[0].pre = -1;
    dp[0].now = -1;
    dp[0].red = 0;
    dp[0].tm = 0;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            cin>>a[i].cn;
            scanf("%d%d",&a[i].del,&a[i].tm);
        }
        init();
        int tem = (1<<n)-1;
        for(int i=1;i<=tem;i++){
            dp[i].red = MAXN;
            for(int j=n-1;j>=0;j--){ //因为是按输入顺序字典序增加的,前优先,则前优先;比如0101->->1111,如果0101->1101->1111与0101->0111->1111代价相同,则A优先B
                int s = 1<<j;         //这里我们判断离1111最近的取值,因为A比D先取了,所以D才是最靠近1111,则先取后段才是我们要求的前优先
                if(i&s){
                    int past = i-s;
                    int red = dp[past].tm+a[j].tm-a[j].del;
                    if(red<0)red = 0;
                    if(dp[i].red>dp[past].red+red){
                        dp[i].red = dp[past].red+red;
                        dp[i].now = j;
                        dp[i].pre = past;
                        dp[i].tm = dp[past].tm+a[j].tm;
                    }
                }
            }
        }
 
        cout<<dp[tem].red<<endl;
        stack <int >s1;

        while(tem){
            s1.push(dp[tem].now);
            tem = dp[tem].pre;
        }
        while(!s1.empty()){
            int tx = s1.top();
            s1.pop();
            cout<<a[tx].cn<<endl;
        }
       // cout<<"debug"<<endl;
    }
    //cout << "Hello world!" << endl;
    return 0;
}
View Code
在一个谎言的国度,沉默就是英雄
原文地址:https://www.cnblogs.com/EdsonLin/p/5366270.html