woj - 将一个问题转换为背包问题
Total Submit: 428 Accepted: 64 Special Judge: No
Xiaoming took the flight MH370 on March 8, 2014 to China to take the ACM contest in WHU. Unfortunately, when the airplane crossing the ocean, a beam of mystical light suddenly lit up the sky and all the passengers with the airplane were transferred to another desert planet.
When waking up, Xiaoming found himself lying on a planet with many precious stones. He found that:
There are n precious stones lying on the planet, each of them has 2 positive values ai and bi. Each time Xiaoming can take the ith of the stones ,after that, all of the stones’ aj (NOT including the stones Xiaoming has taken) will cut down bi units.
Xiaoming could choose arbitrary number (zero is permitted) of the stones in any order. Thus, he wanted to maximize the sum of all the stones he has been chosen. Please help him.
First line of each test case consists of one integer n with 1 <= n <= 1000.
Then each of the following n lines contains two values ai and bi.( 1<= ai<=1000, 1<= bi<=1000)
Input is terminated by a value of zero (0) for n.
100 100
3
2 1
3 1
4 1
0
6
Source
题意 :给你n堆石子,当取走其中的一个后会使剩余所有的石子的费用全部减少当前石子的 b 值,可以选取任意数量的石子,问最终能够取得的最大收益是多少。
思路分析: 这个问题倒着去想比较方便,当取倒数第一个石子时,此时他不会影响任何石子,当取倒数第二个石子时,此时他所能影响的只有倒数第一个,想到这个,dp的转移方程就很明白了, dp[i][j] 表示当枚举到第 i 个石子的时候,此时这个石子作为倒数第 j 个石子的最大收益,则由转移方程
d[i][j]=max(d[i-1][j],d[i-1][j-1]+ai-(j-1)*bi)
在选取的时候,因为当前的情况是会影响后面的,若让这个过程最优,则需要你去贪心一下,对全部的石子排一个序,b值较小的往前面放,b值相同时,a值较大的往前面放。
代码示例:(未测试)
struct node { int a, b; bool operator< (const node &v){ if (b == v.b) return a < v.a; return b > v.b; } }pre[1005]; int dp[1005][1005]; int main() { //freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); int n; while(~scanf("%d", &n) && n){ for(int i = 1; i <= n; i++){ scanf("%d%d", &pre[i].a, &pre[i].b); } memset(dp, 0, sizeof(dp)); for(int i = 1; i <= n; i++){ for(int j = 1; j <= i; j++){ dp[i][j] = max(dp[i-1][j], dp[i-1][j-1]+pre[i].a-(j-1)*pre[i].b); } } int ans = 0; for(int i = 1; i <= n; i++) ans = max(ans, dp[n][i]); printf("%d\n", ans); } return 0; }