[APIO2009]抢掠计划 解题报告

这道题码的十分痛苦。

题目链接

思路:tarjan缩点,重新建图,点权转边权,边权变为负值,跑一遍spfa求最长路即可。

思路很简单,但是码量有点痛苦,打了一百行,打两个板子就发现了许多问题,例如:程序出错的时候不知道是哪里出了问题,找错十分麻烦。我自己出现的错误还是挺多的,模板不是很熟悉。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=500009;
struct Edge{
    int next,to,dis;
}e[N],E[N];
int n,m,num,NUM,s,p,co,top,cnt,l,r;
int head[N],far[N],HEAD[N],ans=0x3f3f3f3f,q[3*N],atm[N],flag[N],pd[N],val[N],stk[N],low[N],dfn[N],col[N],vis[N];
void add(int u,int v){
    e[++num].to=v;
    e[num].next=head[u];
    head[u]=num;
}
void ADD(int u,int v,int w){
    E[++NUM].to=v;
    E[NUM].dis=w;
    E[NUM].next=HEAD[u];
    HEAD[u]=NUM;
}
void tarjan(int u){
    low[u]=dfn[u]=++cnt;
    stk[++top]=u;
    vis[u]=1;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(!dfn[v]){
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else
            if(vis[v]){
                low[u]=min(low[u],dfn[v]);
            }
        }
    if(low[u]==dfn[u]){
        col[u]=++co;
        vis[u]=0;
        val[co]+=atm[u];
        while(stk[top]!=u){
            col[stk[top]]=co;
            val[co]+=atm[stk[top]];
            vis[stk[top]]=0;
            top--;
        }
        top--;
    }
}
void spfa(){
    l=0;r=1;
    for(int i=1;i<=co;i++)
    far[i]=0x3f3f3f3f;
    q[1]=col[s];
    far[col[s]]=-val[col[s]];
    while(l<=r){
    l++;
    int now=q[l];
    pd[now]=0;
    for(int i=HEAD[now];i;i=E[i].next){
        int v=E[i].to;
        if(far[now]+E[i].dis<far[v]){
            far[v]=far[now]+E[i].dis;
            if(!pd[v]){
            r++;
            pd[v]=1;
            q[r]=v;
            }
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&atm[i]);
    scanf("%d%d",&s,&p);
    for(int i=1;i<=p;i++){
        int k;
        scanf("%d",&k);
        flag[k]=1;
    }
    for(register int i=1;i<=n;i++)
    if(!dfn[i])tarjan(i);
    for(register int u=1;u<=n;u++)
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(col[v]!=col[u])
        ADD(col[u],col[v],-val[col[v]]);
    }
    spfa();
    for(int i=1;i<=n;i++)
    if(flag[i]&&ans>far[col[i]])
    ans=far[col[i]];
    printf("%d",-ans);
    return 0;
}

以前只做过 tarjan+树型dp的,这道题是tarjan + spfa 的。

原文地址:https://www.cnblogs.com/sky-zxz/p/9669921.html