luogu3563 逛公园

Posted poorpool

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3563 逛公园相关的知识,希望对你有一定的参考价值。

两遍 spfa 然后建立分层图拓扑排序 dp 一下。
写得很差劲。效率很低。
时间复杂度 \(\mathrm{O}(Tnk)\)
参见这里秒懂。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
int T, n, m, k, p, cnt[2], hea[2][100005], dis[2][100005], uu, vv, ww, he[5100005], cn, dp[5100005];
int ind[5100005], f[100005][55];
bool vis[5100005];
queue<int> d;
struct Edge{
    int too, nxt, val;
}edge[2][200005], edg[10200005];
void rn(int &x){
    char ch=getchar();
    x = 0;
    while(ch<‘0‘ || ch>‘9‘) ch = getchar();
    while(ch>=‘0‘ && ch<=‘9‘){
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
}
void add_edge(int rr, int fro, int too, int val){
    edge[rr][++cnt[rr]].nxt = hea[rr][fro];
    edge[rr][cnt[rr]].too = too;
    edge[rr][cnt[rr]].val = val;
    hea[rr][fro] = cnt[rr];
}
void add_edg(int fro, int too){
    edg[++cn].nxt = he[fro];
    edg[cn].too = too;
    he[fro] = cn;
}
void init(){
    rn(n); rn(m); rn(k); rn(p);
    memset(he, 0, sizeof(he));
    memset(dp, 0, sizeof(dp));
    memset(hea, 0, sizeof(hea));
    memset(vis, 0, sizeof(vis));
    memset(ind, 0, sizeof(ind));
    memset(dis, 0x3f, sizeof(dis));
    dis[0][1] = dis[1][n] = cnt[0] = cnt[1] = cn = 0;
    dp[1] = 1;
    for(int i=1; i<=m; i++){
        rn(uu); rn(vv); rn(ww);
        add_edge(0, uu, vv, ww);
        add_edge(1, vv, uu, ww);
    }
    int qwq=0;
    for(int i=1; i<=n; i++)
        for(int j=0; j<=k; j++)
            f[i][j] = ++qwq;
}
void spfa(int rr){
    d.push(rr?n:1);
    vis[rr?n:1] = true;
    while(!d.empty()){
        int x=d.front();
        d.pop();
        vis[x] = false;
        for(int i=hea[rr][x]; i; i=edge[rr][i].nxt){
            int t=edge[rr][i].too;
            if(dis[rr][t]>dis[rr][x]+edge[rr][i].val){
                dis[rr][t] = dis[rr][x] + edge[rr][i].val;
                if(!vis[t]){
                    vis[t] = true;
                    d.push(t);
                }
            }
        }
    }
}
void build(){
    for(int i=1; i<=n; i++)
        for(int j=0; j<=k; j++)
            if(dis[0][i]+dis[1][i]+j<=dis[0][n]+k)
                vis[f[i][j]] = true;
    for(int i=1; i<=n; i++)
        for(int j=0; j<=k; j++)
            if(vis[f[i][j]])
                for(int l=hea[0][i]; l; l=edge[0][l].nxt){
                    int t=edge[0][l].too, v=j+dis[0][i]+edge[0][l].val-dis[0][t];
                    if(v<=k && f[t][v]){
                        add_edg(f[i][j], f[t][v]);
                        ind[f[t][v]]++;
                    }
                }
}
void topsort(){
    for(int i=1; i<=n; i++)
        for(int j=0; j<=k; j++)
            if(vis[f[i][j]] && !ind[f[i][j]])
                d.push(f[i][j]);
    while(!d.empty()){
        int x=d.front();
        d.pop();
        for(int i=he[x]; i; i=edg[i].nxt){
            int t=edg[i].too;
            ind[t]--;
            if(ind[t]==0)   d.push(t);
            dp[t] = dp[t]+dp[x]>=p?dp[t]+dp[x]-p:dp[t]+dp[x];
        }
    }
}
int chk(){
    for(int i=1; i<=f[n][k]; i++)
        if(ind[i]!=0)
            return -1;
    int re=0;
    for(int i=0; i<=k; i++)
        re = re+dp[f[n][i]]>=p?re+dp[f[n][i]]-p:re+dp[f[n][i]];
    return re;
}
int main(){
    cin>>T;
    while(T--){
        init();
        spfa(0);
        spfa(1);
        build();
        topsort(); 
        printf("%d\n", chk());
    }
    return 0;
}

以上是关于luogu3563 逛公园的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P3953 逛公园(最短路+记忆化搜索)

[Luogu] 逛公园

[luogu P3953] [noip2017 d1t3] 逛公园

Luogu P3953NOIP2017逛公园最短路+拓扑排序+动态规划

luogu 3953 逛公园

luogu P4513ybtoj线段树课堂过关例题3小白逛公园