1. 程式人生 > >hgoi#2019/2/16--t3--psolve

hgoi#2019/2/16--t3--psolve

pso 解法 做出 難題 狀態 %d i++ ax1 所有

技術分享圖片

題目描述

Dustar有n道題目要做。他的月薪是m元。

由於題目是一流的難題,所以Dustar不得不找個人來幫(代)助(替)他寫作業。

找人寫作業不是免費的,但是他們能保證在一個月內做出任何題目。每做一道題需要兩筆付款,第一筆ai元在做題的那一個月初支付,第二筆b[i]元(1<=b[i]<=m)在做完後的下一個月初支付。每一個月Dustar用上一個月掙的錢來付款。

Dustar沒有任何存款意識,所以每個月的節余都回拿用去買糖吃掉了。

因為題目是相互關聯的,它們必須按順序解出。比如,題目3必須在題目4之前或同一個月解出。

請問做完所有題目並支付完所有款項的最少月數。

解法

第一眼看到這道題會想到貪心,如果當前可以放到下一個月裏去,但是這樣很明顯是錯的。。。

試試這組數據

10 9
1 9
9 1

這樣就會被卡住,那麽怎麽做?

那麽就是DP。我們設置\(f[i][j]\)表示到第\(i\)天買了\(j\)物品的答案。

我們每次看一下前後天是否滿足狀態就好了。

ac代碼

#include<bits/stdc++.h>
#define N 305
using namespace std;
int f[N][N],a[N],b[N];
int n,m;
int r(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
int main(){
    m=r(),n=r();
    for(int i=1;i<=n;i++)a[i]=r(),b[i]=r();
    memset(f,-1,sizeof(f));
    f[1][0]=m;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++) {
            if(f[i][j]<0) break;
            int res1=f[i][j],res2=m;
            f[i+1][j]=max(f[i+1][j],m);
            for(int k=j+1;k<=n;k++){
                if(res1-a[k]<0||res2-b[k]<0) break;
                res1-=a[k],res2-=b[k];
                f[i+1][k]=max(f[i+1][k],res2);
            }
        }
    }
    int ans;
    for(int i=1;i<=2*n;i++){
        if(f[i][n]!=-1){ans=i;break;}
    }
    printf("%d\n",ans+1);
    return 0;
}

hgoi#2019/2/16--t3--psolve