题意:
给定n<=1000个小兵,A每次都能使小兵掉1点血,B每次能使所有小兵掉1点血,A、B轮流攻击,每次轮到A他会选择是否攻击,轮到B必须攻击。求A最多能杀死多少小兵。(当小兵血量为1时被攻击到视为被杀死)
思路:
如果所有小兵血量都不一样,A必定能杀死所有小兵。如果有小兵血量相同,那么A必定会攻击一些小兵使他们血量不同。所以我们可以把A的攻击分为两类:用来刚好杀死小兵的一次, 和用来使小兵血量不同的攻击。
我们可以用贪心的思想预处理出怎样用最小的攻击次数让小兵的血量都不同。
然后我们可以用DP[i][j]表示在B第 i 次攻击的时候A攻击了 j 次时,A能杀死的最多小兵数量。这样,A没有攻击的次数,可以留到后面,让后面的小兵血量变得不同。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #include <string> 8 #include <queue> 9 #include <stack> 10 #include <vector> 11 #include <map> 12 #include <set> 13 #include <functional> 14 #include <cctype> 15 #include <time.h> 16 17 using namespace std; 18 19 const int INF = 1<<30; 20 const int MAXN = 1055; 21 22 int a[MAXN]; 23 int b[MAXN]; 24 int dp[MAXN]; 25 int n, MAX; 26 27 void solve() { 28 scanf("%d", &n); 29 for (int i = 0; i < n; i++) scanf("%d", &a[i]); 30 sort(a, a+n); 31 memset(b, 0, sizeof(b)); 32 for (int i = 0; i < n; i++) 33 for (int j = a[i]; j > 0; j--) 34 if (!b[j]) { 35 b[j] = a[i]; 36 break; 37 } 38 memset(dp, 0, sizeof(dp)); 39 for (int i = 1; i <= a[n-1]; i++) if (b[i]>0) { 40 for (int j = i; j >= b[i]-i+1; j--) { 41 dp[j] = max(dp[j], dp[j-b[i]+i-1]+1); 42 } 43 } 44 int ans = 0; 45 for (int i = 0; i <= a[n-1]; i++) 46 ans = max(ans, dp[i]); 47 printf("%d ", ans); 48 } 49 50 int main() { 51 #ifdef Phantom01 52 freopen("HDU4976.txt", "r", stdin); 53 #endif //Phantom01 54 55 int T; 56 scanf("%d", &T); 57 for (int i = 1; i <= T; i++) { 58 printf("Case #%d: ", i); 59 solve(); 60 } 61 62 return 0; 63 }