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



上一篇:[NOIP2013TG]火柴排队 题解


下一篇:【洛谷】P1144 最短路计数