1. 程式人生 > >APOI2009-搶掠計劃

APOI2009-搶掠計劃

atm 計算 spa 情況 結束 pic user stdlib.h getc

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\n",ans);
    return 0;
}

APOI2009-搶掠計劃