hdu 4976 A simple greedy problem.

题意:

有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);
    }

}


posted @ 2017-07-19 09:29  jzdwajue  阅读(90)  评论(0编辑  收藏  举报