UVA 12589 Learning Vector(01揹包+貪心(微擾))
阿新 • • 發佈:2020-08-26
題目大意
給n個向量從中選出k個向量,使得它們首尾連線與x軸成的面積的2倍最大。
解題思路
首先我們觀察圖形可以發現,每新加一個向量,影象右上角的橫縱座標都會變化,而且計算面積的時候需要知道前面的縱座標,所以我們可以dp影象的縱座標,其值就是面積,然後取最大面積。既然是從n個數中選出k個數,很明顯就是一個01揹包模型。
但是還沒完,還要考慮新增的順序問題,這裡我們用微擾(臨項交換)來解。設前面所選方案所得的高度為h,然後又選了兩個座標,分別是\((x_i,y_i),(x_j,y_j)\),我們計算出這個方案的結果,然後再交換兩個座標的順序再計算一遍結果,讓兩個結果做差,發現結果和斜率有關。
交換前面積\(S_1 = 2(hx_i)+x_iy_i+2(h+y_i)x_j+x_jy_j\)
交換後面積\(S_2 = 2(hx_j)+x_jy_j+2(h+y_j)x_i+x_iy_i\)。
\(S_1-S_2 = x_jy_i - x_iy_j\)。顯然,如果要第一個方案比二個更優就要把斜率大的放前面。
程式碼
const int maxn = 2500+10; const int maxm = 2e2+10; struct INFO { int x, y; } a[55]; ll dp[55][2505]; int n, m, kase; int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); int sum = 0; for (int i = 1; i<=n; ++i) { scanf("%d%d", &a[i].x, &a[i].y); sum += a[i].y; } clr(dp, -1); dp[0][0] = 0; sort(a+1, a+n+1, [](INFO a1, INFO a2) {return a2.x*a1.y>a1.x*a2.y;}); ll ans = 0; for (int i = 1; i<=n; ++i) for (int j = m; j>=1; --j) for (int k = sum; k>=a[i].y; --k) if (dp[j-1][k-a[i].y]>=0) { dp[j][k] = max(dp[j][k], dp[j-1][k-a[i].y]+2LL*a[i].x*(k-a[i].y)+1LL*a[i].x*a[i].y); ans = max(ans, dp[j][k]); } printf("Case %d: %lld\n", ++kase, ans); } return 0; }