首页 > 代码库 > 【tarjan+SPFA】BZOJ1179-[Apio2009]Atm

【tarjan+SPFA】BZOJ1179-[Apio2009]Atm

【题目大意】

给出一张有点权的有向图,已知起点和可以作为终点的一些点,问由起点出发,每条边和每个点可以经过任意多次,经过点的权值总和最大为多少。

【思路】

由于可以走任意多次,显然强连通分量可以缩点。然后就是一张DAG图,跑SPFA最长路就好了。

听说Dijkstra写最长路会发生一些奇特的化学反应并且炸掉,还没想清楚姑且笔记一下。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int MAXN=500000+50;
  4 struct edge
  5 {
  6     int to,len;
  7 };
  8 int n,m,s,p,money[MAXN],bar[MAXN],u[MAXN],v[MAXN];
  9 vector<int> E[MAXN];
 10 vector<edge> rE[MAXN];
 11 stack<int> S;
 12 queue<int> que;
 13 int instack[MAXN],low[MAXN],dfn[MAXN],sum[MAXN],col[MAXN],cnt,tot;
 14 int dis[MAXN],inque[MAXN];
 15 
 16 void addedge(int u,int v)
 17 {
 18     E[u].push_back(v);
 19 }
 20 
 21 void addedge2(int u,int v,int w)
 22 {
 23     rE[u].push_back((edge){v,w});
 24 }
 25 
 26 void tarjan(int x)
 27 {
 28     dfn[x]=low[x]=++cnt;
 29     instack[x]=1;
 30     S.push(x);
 31     for (int i=0;i<E[x].size();i++)
 32     {
 33         int to=E[x][i];
 34         if (!instack[to])
 35         {
 36             tarjan(to);
 37             low[x]=min(low[x],low[to]); 
 38         }
 39         else if (instack[to]==1)
 40         {
 41             low[x]=min(low[x],dfn[to]);
 42         }
 43     }
 44     
 45     if (dfn[x]==low[x])
 46     {
 47         tot++;
 48         int tmp;
 49         do
 50         {
 51             tmp=S.top();S.pop();
 52             sum[tot]+=money[tmp];
 53             col[tmp]=tot;
 54             instack[tmp]=2;
 55         }while (tmp!=x);
 56     }
 57 }
 58 
 59 void spfa(int start)
 60 {
 61     memset(inque,0,sizeof(inque));
 62     for (int i=1;i<=tot;i++) dis[i]=0;
 63     dis[start]=sum[start];
 64     inque[start]=1;
 65     que.push(start);
 66     while (!que.empty())
 67     {
 68         int head=que.front();que.pop();
 69         inque[head]=0;
 70         for (int i=0;i<rE[head].size();i++)
 71         {
 72             int to=rE[head][i].to,len=rE[head][i].len;
 73             if (dis[to]<dis[head]+len)
 74             {
 75                 dis[to]=dis[head]+len;
 76                 if (!inque[to])
 77                 {
 78                     inque[to]=1;
 79                     que.push(to);
 80                 }
 81             }
 82         }
 83     }
 84 }
 85 
 86 void rebuild()
 87 {
 88     for (int i=1;i<=m;i++)
 89         if (col[u[i]]!=col[v[i]]) addedge2(col[u[i]],col[v[i]],sum[col[v[i]]]);
 90 }
 91 
 92 void init()
 93 {
 94     scanf("%d%d",&n,&m);
 95     for (int i=1;i<=m;i++)
 96     {
 97         scanf("%d%d",&u[i],&v[i]);
 98         addedge(u[i],v[i]);
 99     }
100     for (int i=1;i<=n;i++) scanf("%d",&money[i]);
101     memset(bar,0,sizeof(bar));
102     scanf("%d%d",&s,&p);
103     for (int i=1;i<=p;i++)
104     {
105         int nowp;
106         scanf("%d",&nowp);
107         bar[nowp]=1;
108     }
109 } 
110 
111 void solve()
112 {
113     cnt=tot=0;
114     memset(instack,0,sizeof(instack));
115     for (int i=1;i<=n;i++)
116         if (!instack[i]) tarjan(i);
117     rebuild();
118     spfa(col[s]);
119     int ans=-1;
120     for (int i=1;i<=n;i++)
121         if (bar[i]) ans=max(ans,dis[col[i]]);
122     printf("%d",ans);
123 }
124 
125 int main()
126 {
127     init();
128     solve();
129     return 0;
130 }

 

【tarjan+SPFA】BZOJ1179-[Apio2009]Atm