1. 程式人生 > >【貪心】家庭作業

【貪心】家庭作業

題目描述
老師在開學第一天就把所有作業都佈置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為10,要求在6天內交,那麼要想拿到這10學分,就必須在第6天結束前交。
每個作業的完成時間都是隻有一天。例如,假設有7次作業的學分和完成時間如下:

老師在開學第一天就把所有作業都佈置了,每個作業如果在規定的時間內交上來的話才有學分。每個作業的截止日期和學分可能是不同的。例如如果一個作業學分為10,要求在6天內交,那麼要想拿到這10學分,就必須在第6天結束前交。
每個作業的完成時間都是隻有一天。例如,假設有7次作業的學分和完成時間如下:

輸入
第一行一個整數N,表示作業的數量;
接下來N行,每行包括兩個整數,第一個整數表示作業的完成期限,第二個數表示該作業的學分。

輸出
輸出一個整數表示可以獲得的最大學分。保證答案不超過C/C++的int範圍。

樣例輸入
複製樣例資料
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
樣例輸出
15

提示
對於20%的資料,N≤103;
對於40%的資料,N≤104;
對於60%的資料,N≤105;
對於100%的資料,N≤106,作業的完成期限均小於7×105

思路分析:按照貪心策略來,一定會把學分高的放在前面,然後進行遍歷,能寫的科目就寫,最後得到的答案一定是最優解.但此題的問題是如何確定目前科目前是否還有空天並把它找出來,樓主之前是想用一個標記陣列以及while(i–)挨個遍歷,沒錯,TLE了…然後接觸了並查集這個玩意----另用一個指向陣列並將一個數指向它前一個數,然後用函式呼叫,如果這個數是空就用它,否則就往前推直到找到下一個空的數,再將標記指向它,下次在用它是就不用一個個找了.

附程式碼:

#include<iostream>
#include<algorithm>
using namespace std;
typedef struct homework
{
	int timelimit, score;
}Homework;
int numb[(int)(1e6 + 5)];				//標記陣列
int before[(int)(1e6 + 5)];				//指向陣列(指向前面第一個空天)
Homework hw[(int)(1e6 + 5)];
int cmp(Homework a, Homework b)
{
	if (a.score == b.score)
		return a.timelimit < b.timelimit;
	else
		return a.score > b.score;
}
int unon(int n)
{
	if (!numb[n])						//定義0為空天,如果這天是空的就直接返回這天
		return n;
	else 
	{
		before[n] = unon(before[n]);		//否則就往前走直到找到空天
		return unon(before[n]);
	}
}
int main()
{
	int n;
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d", &hw[i].timelimit, &hw[i].score);
			before[i] = i-1;
		}
		sort(hw+1, hw+1 + n, cmp);			//將每門學科按照學分排序
		memset(numb, 0, n * sizeof(int));		
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
			int yet = unon(hw[i].timelimit);
			if (yet)
			{
				numb[yet] = 1;
				sum += hw[i].score; 
				if (yet != hw[i].timelimit)					//實現指向最前面的空天
					before[hw[i].timelimit] = before[yet];
			}
		}
		printf("%d\n", sum);
	}
	return 0;
}