1. 程式人生 > 其它 >E. Not Escaping 題解(dp)

E. Not Escaping 題解(dp)

題目連結

題目思路

這個題意有點難說清,還是自己讀比較好

這個題目我覺得是比較套路的,首先只有\(2*k+2\)個點有用

一個起點加上終點再加上梯子兩邊的起始點

問題是如何建邊是一個問題,暴力建邊顯然會達到\(n^2\)

主要是在每一行內可以進行\(dp\)轉移,一次從左往右,一次從右往左,一個有點意思的\(dp\)

程式碼

#include<bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e6+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m,k;
int cnt;
vector<pii> g[maxn];
pii to[maxn];
ll x[maxn];
ll dp[maxn];
void init(){
    for(int i=1;i<=cnt;i++){
        to[i]={0,0};
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        g[i].clear();
    }
}
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++){
            scanf("%d",&x[i]);
        }
        init();
        g[1].push_back({1,++cnt});
        for(int i=1,a,b,c,d,h;i<=k;i++){
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&h);
            g[a].push_back({b,++cnt});
            g[c].push_back({d,++cnt});
            to[cnt-1]={cnt,-h};// 建邊
        }
        g[n].push_back({m,++cnt});
        for(int i=1;i<=cnt;i++){
            dp[i]=INF;
        }
        dp[1]=0;
        for(int i=1;i<=n;i++){
            sort(g[i].begin(),g[i].end());
            int sz=g[i].size();
            for(int j=1;j<sz;j++){
                dp[g[i][j].se]=min(dp[g[i][j].se],dp[g[i][j-1].se]+x[i]*(g[i][j].fi-g[i][j-1].fi));
            }
            for(int j=sz-2;j>=0;j--){
                dp[g[i][j].se]=min(dp[g[i][j].se],dp[g[i][j+1].se]+x[i]*(g[i][j+1].fi-g[i][j].fi));
            }
            for(int j=0;j<sz;j++){
                dp[to[g[i][j].se].fi]=min(dp[to[g[i][j].se].fi],dp[g[i][j].se]+to[g[i][j].se].se);
            }
        }
        if(dp[cnt]>=1e18){
            printf("NO ESCAPE\n");
        }else{
            printf("%lld\n",dp[cnt]);
        }
    }
    return 0;
}
// 3 1 3 2



不擺爛了,寫題