1. 程式人生 > >Doing Homework HDU - 1074 (狀壓dp確定最佳分配順序)

Doing Homework HDU - 1074 (狀壓dp確定最佳分配順序)

題意:要求排出扣分最小的順序,如果有多個,則按字典序最小輸出。

思路:用二進位制狀壓表示有沒有選,考慮從小到大進行更新,也就是說先確定做一個作業的最小扣分,再繼續更新到做兩個作業的最小扣分.....這樣最後求(1<<n)-1的值,就是最小的扣分。

狀態轉移,列舉最後一個加入的作業即可,也就是說當前作業完成情況是sta,最後一個選的是i,那麼前一個狀態應該是sta-(1<<i).

考慮由sta-(1<<i)轉移到sta就行。

又因為給出的資料是按字典序給出的,所以我們到過來進行dp,記錄前驅,最後反向輸出就可以得到正確答案了。

總結:這型別小資料確定最佳分配順序的題目,套路就是按狀壓來dp,轉移方程很簡單,考慮列舉最後一個值選的是誰就行。

程式碼:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+9;
typedef long long ll;
struct Point
{
    string name;
    int deadline;
    int cost;
}p[30];
struct DP
{
    int score;
    int time;
    int pre;
    int id;
}dp[1<<20];
int n;
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            cin>>p[i].name>>p[i].deadline>>p[i].cost;
        }
        int up=(1<<n)-1;
        __builtin_memset(dp,127,sizeof(dp));
        dp[0].score=0,dp[0].time=0,dp[0].pre=-1,dp[0].id=-1;
        for(int s=1;s<=up;s++)
        {
            for(int i=n-1;i>=0;i--)
            {
                if(s&(1<<i))
                {
                    int oldsta=s-(1<<i);
                    int ls=dp[oldsta].time+p[i].cost;
                    int d=ls-p[i].deadline;
                    int add;
                    if(d<0)  add=0;
                    else add=d;
                    if(dp[oldsta].score+add<dp[s].score)
                    {
                        dp[s].score=dp[oldsta].score+add;
                        dp[s].time=ls;
                        dp[s].pre=oldsta;
                        dp[s].id=i;
                    }
                }
            }
        }
        printf("%d\n",dp[up].score);
        int sta=up;
        stack<string> st;
        while(sta!=0)
        {
            string tmp=p[dp[sta].id].name;
            st.push(tmp);
            sta=dp[sta].pre;
        }
        while(st.empty()==0)
        {
            cout<<st.top()<<endl;
            st.pop();
        }
    }
    return 0;
}