POJ1260-Pearls【貪心的錯誤與dp的思路】

題目大意

大致題意:

給出幾類珍珠,以及它們的單價,要求用最少的錢就可以買到相同數量的,相同(或更高)質量的珍珠。

【規定買任一類的珍珠n個(價格爲p),都要支付(n+10)p的錢,即額外支付10p】

樣例分析

例如樣例Input的第二個例子:

3

1 10

1 11

100 12

需要買第一類1個,第二類1個,第三類100個

按常規支付爲 (1+10)*10 + (1+10)*11 + (100+10)*12 = 1551元(一共買了102個珍珠)

但是如果全部都按照第三類珍珠的價格支付,同樣是買102個,而且其中總體質量還被提高了,但是價格卻下降了:(102+10)*12 = 1344元

而對於樣例Input的第一個例子:

2

100 1

100 2

按常規支付爲 (100+10)*1 + (100+10)*2 =330元

但是全部按第二類珍珠的價格支付,同樣買200個,雖然總體質量提升了,但是價格也提高了: (202+10)*2=424元

貪心爲什麼錯

一開始想過從頭到尾遍歷珍珠的價格和數目,每次都看相臨的兩個,如果把當前這一批放入下一個等級價格降低,則將他放到下一個等級,否則直接算在當前等級的買的價格加到答案中,最後一等後設置最大值,保證不會再向後放.,但是這樣的思路其實是錯誤的,以下是證明:

價格pa<pb<pcpa<pb<pc
假設貪心得出(a+10)pa>apb(a+10)pa>a*pb(a+b+10)pb>(a+b)pc(a+b+10)pb>(a+b)*pc兩個前提
但是對於(a+10)pa+(b+c+10)pc<(a+b+c+10)pc(a+10)*pa+(b+c+10)*pc<(a+b+c+10)*pc即不採取歸併更小的情況是否存在呢
化簡式子:
(a+10)pa<(a+b)pc(a+10)*pa<(a+b)*pc

對比條件,我們知道(a+10)pa>apb(a+b+10)pb>(a+b)pc(a+10)*pa>a*pb和(a+b+10)pb>(a+b)*pc

完全可以有apb<(a+10)pa<(a+b)pc<(a+b+10)pba*pb<(a+10)*pa<(a+b)*pc<(a+b+10)*pb

所以貪心策略是錯的

爲什麼可以dp以及dp的證明

首先證明最優解中肯定不會有交叉的替換,即在質量爲a<b<j<c<d的情況下,如果a被c替換,那麼b也一定要被c替換 假設在最優解中存在:a被c替換且b不被c替換的情況:

1.b不被任何替換 那麼此時把a換成用b替換 得到比原來更優的解,錯誤
2.b被j替換,此時把a換成用j替換 得到比原來更優的解,錯誤
3.b被d替換,此時把b換成用c替換 得到比原來更優的解,錯誤

因此,不存在交叉的替換,那麼最優解分爲下面兩種情況:
1.不存在斷點,即所有的都用最大一種替換,dp[c]=(a[1]+...+a[c]+10)p[c]dp[c]=(a[1]+...+a[c]+10)*p[c]
2.存在斷點,最後一個斷點爲i,那麼最優解必爲dp[i]+(a[i+1]+..+a[c]+10)p[c]dp[i]+(a[i+1]+..+a[c]+10)*p[c]

每個點都有可能是最後一個斷點,因此產生了我們的DP方程:
dp[i]=min(dp[j]+(a[j+1]+..+a[i]+10)p[i]dp[i]=min(dp[j]+(a[j+1]+..+a[i]+10)*p[i])
把dp[0]設成0的話 2就包含了1 dp[c]就是最後的答案

有點像最長上升子序列的問題

int T, N, a[MAX], p[MAX], dp[MAX];
int main() {
	cin >> T;
	while (T--) {
		cin >> N;
		for (int i = 1; i <= N; i ++ )cin >> a[i] >> p[i];
		memset(dp, 0, sizeof(dp));
		for (int i = 1; i <= N; i++) {
			int cnt = inf, sum = 0;
			for (int j = i; j > 0; j--) {
				sum += a[j];
				cnt = min(cnt, dp[j - 1] + (sum + 10)*p[i]);
			}
			dp[i] = cnt;
		}
		cout << dp[N] << endl;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章