1. 程式人生 > >hdu 1074

hdu 1074

acm

狀態壓縮題,要註意的是有多種情況扣分相同,那麽要按照字典序輸出,也就是輸入時在前,那麽輸出也要在前。具體看代碼註釋。
參考文章:

  • http://www.voidcn.com/article/p-fsgosnqv-bpb.html
  • http://www.cnblogs.com/kuangbin/archive/2011/08/04/2127687.html
  • http://www.cnblogs.com/qkhhxkj/archive/2011/06/29/2093894.html

#include <iostream>
#include <stdio.h>
#include <string>
#include <stack>
using namespace std;

const int maxn=1<<17;
struct homework{
    char name[150];
    int deadline;
    int timecost;//做作業所花費的時間
}h[30];
struct node{
    int score;//當前的扣分情況
    int time;//當前所花的天數
    int num;//當前所做作業的序號
    int pre;//上一個狀態的地址
}dp[maxn];//數組要開的足夠大,數字上限為2^n

int main(){
    int T,N;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        for(int i=0;i<N;i++)    scanf("%s%d%d",&h[i].name,&h[i].deadline,&h[i].timecost);
        dp[0].score=0;
        dp[0].time=0;
        int M=(1<<N)-1;
        for(int i=1;i<=M;i++){//用二進制的0~n-1位來表示作業1~n的完成情況,0為都沒有完成,(1<<N)-1表示所有作業都完成,這裏進行遍歷
            dp[i].score=100000;//保證dp[i]得到初始化
            for(int j=N-1;j>=0;j--){//j從大到小每個作業遍歷,保證字典序輸出
                int temp=1<<j;
                if((i&temp)==temp){//表示當前作業狀態是做了j號作業的
                    int k=i-temp;//表示上一個狀態,也就是沒有做j號作業,其余與這個狀態一樣
                    int x=dp[k].time+h[j].timecost-h[j].deadline;
                    if(x<0)
                        x=0;//計算做j號作業是否逾期,若沒有預期逾期則不扣分
                    if(dp[k].score+x<dp[i].score){//若為扣分最少的情況,則更改信息
                        dp[i].score=dp[k].score+x;
                        dp[i].num=j;
                        dp[i].time=dp[k].time+h[j].timecost;
                        dp[i].pre=k;
                    }
                }
            }
        }
        printf("%d\n",dp[M].score);
        stack<int>st;
        while(M!=0){
            st.push(dp[M].num);
            M=dp[M].pre;
        }
        while(!st.empty()){
            printf("%s\n",h[st.top()].name);
            st.pop();
        }

    }
    return 0;
}

確實不是很懂這題,出錯的地方請見諒。

hdu 1074