1. 程式人生 > 其它 >Luogu6005 [USACO20JAN]Time is Mooney G 題解

Luogu6005 [USACO20JAN]Time is Mooney G 題解

題目傳送門

第一眼看到題面時可能覺得需要用 dijstra 或分層圖之類,但注意到資料範圍很小(都是 \(\leqslant1000\)),因此考慮好寫的 DP

首先當然需要使用鄰接表存圖。

不妨設 \(f_{i,j}\) 為第 \(i\) 天在第 \(j\) 個城市所獲利潤,易得狀態轉移方程

\[f_{i,j}=\max(f_{i,j},f_{i-1,e[i].to}) \]

但是這還沒完,還有兩個問題需要解決:

  1. 會以 \(T^2\times C\) 的速度扣錢。

    不妨在每次外層迴圈後處理 \(ans\),有:

    \[ans=\max(ans,f[i][1]-c\times i^2); \]
  2. 外層迴圈沒有明確邊界。

    最大是 \(1000\),以此為邊界即可。注意:有的人可能習慣設 \(N=1010\) ,這會導致 \(i=N\) 時 RE,應該 \(N-10\)

View code:

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

#define int long long
#define ri register int
#define il inline

const int INF=0x7fffffff,N=1010;
int n,m,c,ans=0;
int v[N];
int cnt,head[N];
int f[N][N];
struct Edge{
    int to,nxt;
}e[N<<2];

il ll read(){
    ll x=0,y=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
            y=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*y;
}

il void add(int u,int v){
    e[++cnt]=(Edge){v,head[u]};
    head[u]=cnt;
}

signed main(){
    memset(f,-1,sizeof(f));
    n=read(),m=read(),c=read();
    for(ri i=1;i<=n;i++)
        v[i]=read();
    for(ri i=1;i<=m;i++){
        int u=read(),v=read();
        add(u,v);//有向圖
    }
    f[0][1]=0;
    for(ri i=1;i<=N-10;i++){
        for(ri j=1;j<=n;j++){
            for(ri k=head[j];k;k=e[k].nxt){
				if(~f[i-1][e[k].to])
					f[i][j]=max(f[i][j],f[i-1][e[k].to]+v[j]);
            }
        }
        ans=max(ans,f[i][1]-(c*i*i));
    }
    printf("%lld",ans);
    return 0;
}