【BZOJ-1179】Atm Tarjan + SPFA

1179: [Apio2009]Atm

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 2407  Solved: 993
[Submit][Status][Discuss]

Description

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的单向的道路到达其中的至少一个酒吧。

 

Source

Solution

挺不错的结合,挺好实现的

首先题目中有环,很显然换上的都可以取到,但这不符合一般的最短/长路的跑法,所以考虑转化

把图中的环缩成一个点,点权为环上的值总和,对缩出来的点重构图,连边

很显然是个DAG,那么如此这样就可以直接跑了,直接上SPFA跑一遍即可,实际上BFS也可以..

最后枚举所有的酒吧,判断在哪里结束获得最大即可

PS:开始重建图的时候,是在原来的基础上建的,为什么RE成狗?迫使我新开一个重新建...

启发:

有向图出现环,很有可能需要缩成点,这个思想可以应用与最短路,或者网络流上

想题要周到,方便实现的写法,往往最适合

遇到DAG时,尝试利用一下DAG的性质,可能会有奇效

Code

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<queue> 
using namespace std; 
#define maxn 500010 
int read() 
{ 
    int x=0,f=1; char ch=getchar(); 
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} 
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} 
    return x*f; 
} 
int n,m,uu,S,P,ans,val[maxn]; 
  
struct Edgenode{int to,next,val;}edge[maxn<<1]; 
int head[maxn<<1],cnt=1; 
void add(int u,int v) 
{cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;} 
struct Roadnode{int to,next;}road[maxn]; 
int last[maxn],cn=1; 
void insert(int u,int v) 
{cn++;road[cn].to=v;road[cn].next=last[u];last[u]=cn;} 
int dfn[maxn],low[maxn],qcnt,stack[maxn],top,num[maxn],belong[maxn],tot,valu[maxn]; 
bool visit[maxn]; 
  
void Tarjan(int x) 
{ 
    dfn[x]=low[x]=++tot; 
    visit[x]=1; stack[++top]=x; 
    for (int i=head[x]; i; i=edge[i].next) 
        { 
            if (!dfn[edge[i].to]) 
                { 
                    Tarjan(edge[i].to); 
                    if (low[edge[i].to]<low[x]) low[x]=low[edge[i].to]; 
                } 
            else 
                if(visit[edge[i].to] && dfn[edge[i].to]<low[x]) 
                    low[x]=dfn[edge[i].to]; 
        } 
    if (dfn[x]==low[x]) 
        { 
            qcnt++; 
            while (x!=uu) 
                uu=stack[top--],num[qcnt]++,visit[uu]=0,belong[uu]=qcnt,valu[qcnt]+=val[uu];  
        } 
} 
void rebuild() 
{ 
    for (int i=1; i<=n; i++) 
        for (int j=head[i]; j; j=edge[j].next) 
            if (belong[i]!=belong[edge[j].to]) 
                insert(belong[i],belong[edge[j].to]); 
} 
#define inf 0x7fffffff 
int dis[maxn]; 
void spfa() 
{ 
    queue<int>que; memset(visit,0,sizeof(visit)); 
//  for (int i=1; i<=qcnt; i++) dis[i]=-inf; 
    visit[S]=1; dis[S]=valu[S]; que.push(S); 
    while (!que.empty()) 
        { 
            int now=que.front(); que.pop(); visit[now]=0; 
            for (int i=last[now]; i; i=road[i].next) 
                if (dis[road[i].to]<dis[now]+valu[road[i].to]) 
                    { 
                        dis[road[i].to]=dis[now]+valu[road[i].to]; 
                        if (!visit[road[i].to]) 
                            visit[road[i].to]=1,que.push(road[i].to); 
                    } 
        } 
} 
bool bar[maxn]; 
int main() 
{ 
    n=read(),m=read(); 
    for (int u,v,i=1; i<=m; i++) u=read(),v=read(),add(u,v); 
    for (int i=1; i<=n; i++) val[i]=read(); 
    for (int i=1; i<=n; i++) if (!dfn[i]) Tarjan(i); 
    S=read(); S=belong[S]; P=read(); 
    for (int x,i=1; i<=P; i++) x=read(),bar[x]=1; 
    rebuild(); spfa(); 
//  for (int i=1; i<=n; i++) 
//      printf("%d\n",dis[belong[i]]); 
    for (int i=1; i<=n; i++) 
        if (bar[i]) ans=max(ans,dis[belong[i]]); 
    printf("%d\n",ans); 
    return 0; 
}

似乎是个不错的NOIP难度题?

posted @ 2016-04-26 23:18  DaD3zZ  阅读(301)  评论(0编辑  收藏  举报