Doing Homework HDU1074 【dp】

 dp,第一次做這種題目,第一天沒有什麼頭緒,看了幾個網上的代碼,有了一定理解,第二晚磕磕碰碰的碼出來了。寫一下題解來理一下思路,順便爲後來找思路的盡一點微薄之力

Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test, 1 day for 1 point. And as you know, doing homework always takes a long time. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.

InputThe input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=15) which indicate the number of homework. Then N lines follow. Each line contains a string S(the subject's name, each string will at most has 100 characters) and two integers D(the deadline of the subject), C(how many days will it take Ignatius to finish this subject's homework).

Note: All the subject names are given in the alphabet increasing order. So you may process the problem much easier.
OutputFor each test case, you should output the smallest total reduced score, then give out the order of the subjects, one subject in a line. If there are more than one orders, you should output the alphabet smallest one.
Sample Input
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3
Sample Output
2
Computer
Math
English
3
Computer
English
Math


        
  
Hint
In the second test case, both Computer->English->Math and Computer->Math->English leads to reduce 3 points, but the 
word "English" appears earlier than the word "Math", so we choose the first order. That is so-called alphabet order.

題意:有n門作業,每個都要花一定時間完成並且有截止日期,超過截止日期的話就會扣分,超過一天扣一分,求最少扣的分數和對應的做作業順序。
思路:因爲只有15門課程,每門作業只有做和沒做兩種狀況,所以最多有(1<<15)-1種狀態(若不清楚二進制運算符,可以看一下 http://www.cnblogs.com/lianchenboke/p/5061032.html )。我們直接枚舉出每個狀態,求其對應的最小值就行。我們尋找在當前狀態下,上一狀態的最小值,然後加上對應的這一門課程所扣的分數就行。最終狀態就是dp[(1<<15)-1]。也就是找到當前所做科目下,找到每少做一門時的扣分加上這門的扣分,小於當前扣分就替換。而找少做一門時,我們應該從最後一門開始遍歷,因爲在扣分相同的情況下,我們要優先選擇前面的科目。因爲最後要找出科目順序,所以我們要用一個數組來儲存每個狀態是做哪一門得來的。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
#define ld long double
#define INF 0x3f3f3f3f
using namespace std;
char name[20][120];
int cost[20],dead_time[20],dp[1<<16],time[1<<16],def[1<<16];  //time用來儲存每個狀態對應的當前時間,dp爲最少扣分,def爲對應上一門科目
void Cout(int num) {                                       //輸出最少狀況下對應的科目順序 
	if(num==0) return ;
	int i=def[num];
	Cout(num-(1<<i));
	cout<<name[def[num]]<<'\n';
}
int main() {
	std::ios::sync_with_stdio(false);
	int T;
	cin>>T;
	while(T--) {
		int n;
		cin>>n;
		for(int i=0; i<n; i++)
			cin>>name[i]>>dead_time[i]>>cost[i];
		dp[0]=0;
		for(int i=1; i<(1<<n); i++) {               //每個狀態
			dp[i]=INF;
			for(int j=n-1; j>=0; j--) {         //先判斷做沒做這個科目,做了的話求不做它時的狀態,進行對比,從後遍歷
				int temp=1<<j;
				if((i&temp)==0) continue;
				int now_cost=time[i-temp]+cost[j]-dead_time[j];
				if(now_cost<0) now_cost=0;          //扣分沒有負的
				if(dp[i]>dp[i-temp]+now_cost) {
					dp[i]=dp[i-temp]+now_cost;
					time[i]=time[i-temp]+cost[j];
					def[i]=j;
				}
			}
		}
		cout<<dp[(1<<n)-1]<<'\n';
		Cout((1<<n)-1);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章