题意:
有n个小兵,每一个小兵有a【i】血量,第一个人每次仅仅能对一个小兵砍一滴血,第二个人每次对全部生存的小兵砍一滴血。最后看第一个人最多能够砍杀几个小兵。
思路:
这个就是游戏中所说的垫刀问题。首先是不一样的越多那么第一个人所补得刀数就越多。
那么就要考虑要多少刀把当前的小兵的血量砍得和别人不一样。
用W【i】表示砍了i刀之后与其它的血量不一样的原始血量
用dp[i][j],表示进行了i组攻击(第一个攻击一次,第二个攻击一次,称为一组)。第一个留有j次攻击,最多能杀死的小兵数目。
那么在第i组攻击的时候j的范围是【0。i+1】 ,由于第一个人能够有i+1次的机会
那么dp转移方程就是 dp【i+1】【t】 = max(dp【i】【j】+1。dp【i+1】【t】)(t = i+ j +1 -w[i+1] )
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 1111 int n; int a[N]; int dp[N][N]; int w[N]; int main(){ int T; int cas = 0 ; scanf("%d",&T); while(T--){ scanf("%d",&n); memset(w,-1,sizeof(w)); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } sort(a+1,a+n+1); //求a【i】边的不一样须要补多少刀 for(int i=1;i<=n;i++){ for(int j=a[i];j>0;j--){ if(w[j]==-1){ w[j] = a[i]; break; } } } for(int i=1;i<=a[n];i++){ printf("%d %d\n",w[i],i); } memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int i=0;i<a[n];i++){ for(int j = 0;j<=i+1;j++){ if(dp[i][j]!=-1){ dp[i+1][j+1] = max(dp[i+1][j+1],dp[i][j]); int ok = j+i+1 - w[i+1]; if(w[i+1]!=-1&&ok>=0){ dp[i+1][ok] = max(dp[i+1][ok],dp[i][j]+1); } } } } /* for(int i = 0;i<=a[n];i++) { for(int j = 0; j <= a[n] ; j ++){ printf("%2d ",dp[i][j]); } puts(""); } */ int ans = 0; for(int j = 0; j <= a[n] ; j ++) ans = max(ans, dp[a[n]][j]); printf("Case #%d: %d\n",++cas,ans); } }
时间: 2024-11-05 19:30:30