APOI2009-抢掠计划

Posted rj-nh

tags:

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

Problem

Description

Siruseri城中的道路都是单向的。不同的道路由路口连接。按照法律的规定,在每个路口都设立了一个Siruseri银行的ATM取款机。令人奇怪的是,Siruseri的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。 Banditji计划实施Siruseri有史以来最惊天动地的ATM抢劫。他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的ATM机,最终他将在一个酒吧庆祝他的胜利。 使用高超的黑客技术,他获知了每个ATM机中可以掠取的现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可以经过同一路口或道路任意多次。但只要他抢劫过某个ATM机后,该ATM机里面就不会再有钱了。 例如,假设该城中有6个路口,道路的连接情况如下图所示:
技术分享图片
市中心在路口1,由一个入口符号→来标识,那些有酒吧的路口用双圈来表示。每个ATM机中可取的钱数标在了路口的上方。在这个例子中,Banditji能抢劫的现金总数为47,实施的抢劫路线是:1-2-4-1-2-3-5。

Input

第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。
接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。
接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号。

Output

输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

Sample Input

6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6

Sample Output

47

Hint

50%的输入保证$N, M$<=3000。
所有的输入保证$N, M$<=500000。
每个ATM机中可取的钱数为一个非负整数且不超过4000。
输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。

Solution

思路

这道题目一眼就可以看出,显然就是缩点+SPFA求最长路.然后就AC了,这么简单?
但是这里还有一个要注意的:

  • 时间戳time不能用这个名字,要换一个

Code

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
using namespace std;
inline int gi(){
    int f=1,sum=0;char ch=getchar();
    while(ch>‘9‘ || ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘ && ch<=‘9‘){sum=sum*10+ch-‘0‘;ch=getchar();}
    return f*sum;
}
const int maxn=500010;
struct node{
    int to,nxt;
}e[maxn],e1[maxn];
int front1[maxn],cnt1,front[maxn],cnt;
void Add1(int u,int v){
    e1[++cnt1]=(node){v,front1[u]};front1[u]=cnt1;
}
void Add(int u,int v){
    e[++cnt]=(node){v,front[u]};front[u]=cnt;
}
int dfn[maxn],low[maxn],sta[maxn],top,in[maxn];
int tim,cou,color[maxn],size[maxn],a[maxn];
void Tarjan(int u){
    dfn[u]=low[u]=++tim;sta[++top]=u;in[u]=1;
    for(int i=front1[u];i;i=e1[i].nxt){
        int v=e1[i].to;
        if(!dfn[v]){
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(in[v])low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        cou++;color[u]=cou;size[cou]+=a[u];
        in[u]=0;
        while(sta[top]!=u){
            int v=sta[top];
            color[v]=cou;size[cou]+=a[v];
            in[v]=0;
            top--;
        }
        top--;
    }
}
int vis[maxn],dis[maxn];
void spfa(int s){
    queue<int >Q;
    while(!Q.empty())Q.pop();
    Q.push(s);vis[s]=1;dis[s]=size[s];
    while(!Q.empty()){
        int u=Q.front();Q.pop();vis[u]=0;
        for(int i=front[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(dis[v]<dis[u]+size[v]){
                dis[v]=dis[u]+size[v];
                if(!vis[v]){
                    vis[v]=1;Q.push(v);
                }
            }
        }
    }
    
}
int main(){
    int i,j,k,n,m;
    n=gi();m=gi();
    for(i=1;i<=m;i++){
        int x=gi(),y=gi();Add1(x,y);
    }
    for(i=1;i<=n;i++)a[i]=gi();
    for(i=1;i<=n;i++)if(!dfn[i])Tarjan(i);
    for(i=1;i<=n;i++)
        for(j=front1[i];j;j=e1[j].nxt){
            int v=e1[j].to;
            if(color[v]!=color[i])Add(color[i],color[v]);
        }
    int S,P;
    S=gi();P=gi();
    spfa(color[S]);
    int ans=0;
    for(i=1;i<=P;i++){
        int p=gi();
        if(dis[color[p]]>ans)ans=dis[color[p]];
    }
    printf("%d
",ans);
    return 0;
}























以上是关于APOI2009-抢掠计划的主要内容,如果未能解决你的问题,请参考以下文章

luogu P3627 [APIO2009]抢掠计划

P3627 [APIO2009]抢掠计划

[APIO2009-C]抢掠计划

[APIO2009]抢掠计划

APIO2009 抢掠计划 Tarjan DAG-DP

p3627[APIO2009] 抢掠计划