剪草

剪草

又一道水題
【問題描述】
有 N 棵小草,編號 0 至 N-1。奶牛 Bessie 不喜歡小草,所以 Bessie 要用剪刀剪草,目標是使
得這 N 棵小草的高度總和不超過 H。在第 0 時刻,第 i 棵小草的高度是 h[i],接下來的每個整數時
刻,會依次發生如下三個步驟:
(1)每棵小草都長高了,第 i 棵小草長高的高度是 grow[i]。
(2)Bessie 選擇其中一棵小草並把它剪平,這棵小草高度變爲 0。注意:這棵小草並沒有死掉,
它下一秒還會生長的。
(3)Bessie 計算一下這 N 棵小草的高度總和,如果不超過 H,則完成任務,一切結束,否則輪
到下一時刻。
你的任務是計算:最早是第幾時刻,奶牛 Bessie 能完成它的任務?如果第 0 時刻就可以完成就
輸出 0,如果永遠不可能完成,輸出-1,否則輸出一個最早的完成時刻。
【輸入】
第一行,一個整數 g,表示有 g 組測試數據,組數不超過四組。每組數據的格式是:
第一行,兩個整數 N 和 H。 1 ≤ N ≤ 50,0 ≤ H ≤ 1000000。
第二行,N 個整數,表示 h[i]。0 ≤ h[i] ≤ 100000。
第三行,N 個整數,表示 grow[i]。1 ≤ grow[i] ≤ 100000。

一開始用了個小貪心
大循環是從小到大每局到第幾天可以結束,因爲可以證明這個次數不超過20,誒雖然不知道怎麼怎麼證
然後從枚舉的這個第i天倒推回去,最後一天減去目前長的最高的,倒數第二天減去當天除去最後一天減掉過的最高的
因爲我們剪掉的高度數永遠不會變,所以可以這麼做

#include<bits/stdc++.h>
using namespace std;

int T;
long long a[60],n,m,gr[60],suma,sumgr,b[60],c[60];
void init()
{
   suma=sumgr=0;
   for (int i=1; i<=n; i++)
      {
        scanf("%lld",&a[i]);
        suma+=a[i];
      }
   for (int i=1; i<=n; i++)
      {
        scanf("%lld",&gr[i]);
        sumgr+=gr[i];
      }
}
int main()
{
  freopen("grass.in","r",stdin);
  freopen("grass.out","w",stdout);
  scanf("%d",&T);
  for (int oo=1; oo<=T; oo++)
  {
    bool ppp=true;
    scanf("%lld%lld",&n,&m);
    init();
    if (suma+sumgr<=m) {printf("0\n"); ppp=false; continue;}
    for (int i=1; i<=n; i++)
      {
        long long sumb=0;
        for (int j=1; j<=n; j++)
          {
            b[j]=a[j]+gr[j]*i;
            c[j]=b[j];
            sumb+=b[j];
          }
        long long p=0;
        for (int j=0; j<i; j++)
          {
            long long maxx=0,maxi=0;
            for (int k=1; k<=n; k++)
              {
                b[k]=c[k]-j*gr[k];
                if (b[k]>maxx) {maxx=b[k]; maxi=k;}
              }
            sumb-=b[maxi];
            c[maxi]=0;
            if (sumb<=m) {p=1; break;}
          }
        if (p==1) {printf("%d\n",i); ppp=false; break;}
      }
    if (ppp==true) printf("-1\n");
  }

}

但是哎,畢竟是貪心,
1 50
10000 10000
1 49

這組數據,貪心舊先減去後面的,但這樣會發現不對,貪心的答案是 3
但是其實先把前面的減掉,再減掉後面的就好了,所以答案是2

所以你應該想到了

DP

畢竟沒法貪心的都用DP,這是鐵律。

dp[i][j] 表示第ij 是否減的最優值。

dp[i][j]=max(dp[i1][j],dp[i1][j1]+grass[i].h+grass[i].growj);


或者
不取

#include<bits/stdc++.h>
using namespace std;
int T,n,H,ans,dp[55][55],hsum,gsum;
struct node{
    int h,grow;
    bool operator < (const node b) const{
        return grow<b.grow;
    }
};
node grass[55];

int main(){
    freopen("grass.in","r",stdin);
    freopen("grass.out","w",stdout);
    scanf("%d",&T);
    while(T--){
        ans=-1;
        scanf("%d%d",&n,&H);
        hsum=gsum=0;
        for(int i=1;i<=n;i++) scanf("%d",&grass[i].h),hsum+=grass[i].h;
        for(int i=1;i<=n;i++) scanf("%d",&grass[i].grow),gsum+=grass[i].grow;
        sort(grass+1,grass+n+1);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                dp[i][j]=max(dp[i-1][j],dp[i-1][j-1]+grass[i].h+grass[i].grow*j);
        for(int t=0;t<=n;t++){
            int sum=hsum+gsum*t;
            if(sum-dp[n][t]<=H){
                ans=t;
                break;
            }
        }
        printf("%d\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章