標籤:style http io ar os sp for on div
題目連結:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1179
個人感覺此題比省選題簡單多了,大概是POJ中檔題的難度。。。
首先我們把這個有向圖縮個點,縮點後的圖是個DAG,新圖中每個點的權值是對應強連通分量中的點的權值之和,新圖中每個點對應的強連通分量中的點都是相互可達的,也就是說新圖中的每個點,劫匪都能一次性搶完其中所有ATM機的錢。
然後對這個新圖跑SPFA,SPFA本來是搞邊權的,在這個題裡,把SPFA稍微改改就能跑點權了,類似於NOIP的最優貿易那個題,很簡單。
最後枚舉所有終點,找出能夠得到最多錢的那個終點就行了。
#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <algorithm>#define MAXE 500050#define MAXV 500050using namespace std;struct edge{ int u,v,next;}edges1[MAXE],edges2[MAXE]; //縮點前的圖、縮點後的圖int nCount1=0,nCount2=0,head1[MAXV],head2[MAXV],money[MAXV]; //money[i]=原圖中點i的錢數int dfn[MAXV],low[MAXV],cnt=0,belong[MAXV],value[MAXV],tot=0; //value[i]=第i號聯通塊中的ATM機金額總數,tot=強連通分量總數bool visit[MAXV];int stack[MAXV],top=0;int n,m,S,P;void AddEdge1(int U,int V){ edges1[++nCount1].u=U; edges1[nCount1].v=V; edges1[nCount1].next=head1[U]; head1[U]=nCount1;}void AddEdge2(int U,int V){ edges2[++nCount2].u=U; edges2[nCount2].v=V; edges2[nCount2].next=head2[U]; head2[U]=nCount2;}void tarjan(int u){ low[u]=dfn[u]=++cnt; visit[u]=true; stack[++top]=u; for(int p=head1[u];p!=-1;p=edges1[p].next) { int v=edges1[p].v; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(visit[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { tot++; int v=-1; while(u!=v) { v=stack[top--]; belong[v]=tot; value[tot]+=money[v]; visit[v]=false; } }}void rebuild() //縮點建立新圖{ for(int u=1;u<=n;u++) for(int p=head1[u];p!=-1;p=edges1[p].next) { int v=edges1[p].v; if(belong[u]!=belong[v]) AddEdge2(belong[u],belong[v]); }}int f[MAXV],q[MAXV]; //f[i]=從起點到點i時搶到的最多錢數bool inQueue[MAXV];void SPFA(){ int h=0,t=1; q[h]=belong[S]; inQueue[belong[S]]=true; f[belong[S]]=value[belong[S]]; while(h<t) { int u=q[h++]; inQueue[u]=false; if(h==MAXV-1) h=0; //迴圈利用隊列,防止RE for(int p=head2[u];p!=-1;p=edges2[p].next) { int v=edges2[p].v; if(f[u]+value[v]>f[v]) { f[v]=f[u]+value[v]; if(!inQueue[v]) { inQueue[v]=true; q[t++]=v; if(t==MAXV-1) t=0; //迴圈利用隊列,防止RE } } } }}int main(){ int ans=0; memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); AddEdge1(u,v); } for(int i=1;i<=n;i++) scanf("%d",&money[i]); for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); scanf("%d%d",&S,&P); rebuild(); //建立縮點後的新圖 SPFA(); for(int i=1;i<=P;i++) { int x; scanf("%d",&x); if(f[belong[x]]>ans) ans=f[belong[x]]; } printf("%d\n",ans); return 0;}
[BZOJ 1179][APIO 2009]Atm