赛后写的,动态规划,学长和题解,提供了两种状态设计的思路,都写了下……结果在写第二种的时候,不小心把下标的起点写错了,导致WA了无数发…… 无奈啊……每次都是这种错误……
题意:
大概就是有n块石头,每块石头有两个值ai和bi,其中ai是价值。要求你从中选任意块,获得的价值最大。
但是,每当你选了一块石头,此时没有被你选到得石头的价值都会剪掉这块石头的bi。
思路:
首先,可以证明,如果被选,bi小的肯定被先选。因为,如果某两块石头,bi大的先选了;那么交换这两块石头的选取顺序,可以得到更大的价值。
因此,我们可以把所有的石头按照bi排序。这样子来贪心。
接下来是动态规划:
状态1:dp[i][j]表示 选取到第i个石头,选到的bi总和是j。 这样的话,在选取下一个石头的时候,那个石头的 ai - j 才是它能获得的价值。
这种解法下的代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAXN = 1030; 8 9 struct node { 10 int a, b; 11 bool operator < (const node & x) const { 12 return b < x.b; 13 } 14 }a[MAXN]; 15 16 int n; 17 int dp[MAXN]; ///dp[i][j] 18 19 int main() { 20 #ifdef Phantom01 21 // freopen("WHU1538.txt", "r", stdin); 22 #endif // Phantom01 23 24 while (scanf("%d", &n)!=EOF) { 25 if (0==n) break; 26 27 for (int i = 0; i < n; i++) 28 scanf("%d%d", &a[i].a, &a[i].b); 29 sort(a, a+n); 30 memset(dp, 0, sizeof(dp)); 31 for (int i = 0; i < n; i++) { 32 for (int j = MAXN-1; j >= 0; j--) { 33 if (a[i].b+j <= 1005) 34 dp[a[i].b+j] = max(dp[a[i].b+j], dp[j]+a[i].a-j); 35 else 36 dp[1006] = max(dp[1006], dp[j]+a[i].a-j); 37 } 38 } 39 int ans = 0; 40 for (int i = 0; i < MAXN; i++) 41 ans = max(ans, dp[i]); 42 printf("%d ", ans); 43 } 44 45 return 0; 46 }
状态2:dp[i][j]表示 选到第i个石头,后面还要选j块石头。 这样子的话,这块石头在整个过程中能够提供的价值是 ai - J * bi
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAXN = 1050; 8 9 struct node { 10 int a, b; 11 bool operator < (const node &x) const { 12 return b < x.b; 13 } 14 }a[MAXN]; 15 16 int n; 17 int dp[MAXN]; 18 19 int main() { 20 #ifdef Phantom01 21 freopen("1538_1.in", "r", stdin); 22 #endif // Phantom01 23 24 while (scanf("%d", &n)!=EOF) { 25 if (0==n) break; 26 27 memset(dp, 0, sizeof(dp)); 28 for (int i = 0; i < n; i++) 29 scanf("%d%d", &a[i].a, &a[i].b); 30 sort(a, a+n); 31 for (int i = 0; i < n; i++) { 32 for (int j = 0; j <= n; j++) { 33 dp[j] = max(dp[j], dp[j+1]+a[i].a-j*a[i].b); 34 } 35 } 36 printf("%d ", dp[0]); 37 } 38 39 return 0; 40 }