【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 }
时间: 2024-10-11 21:51:38

【tarjan+SPFA】BZOJ1179-[Apio2009]Atm的相关文章

【强连通分量+spfa】Bzoj1179 Apio2009 Atm

Description Sulotion 显然缩强连通分量,然后求最长路,虽然是DAG但还是有点麻烦,于是用了spfa. Code 重建图_数组写错好多次,感觉做这题也就是练了一下实现. 1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int maxn=5e+5; 5 6 int pre[maxn],low[maxn],clock; 7 int scc[maxn],val[maxn],c

【强联通分量缩点】【最短路】【spfa】bzoj1179 [Apio2009]Atm

缩点后转化成 DAG图上的单源最长路问题.spfa/dp随便. 1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 using namespace std; 7 int cmp[500001],sum,n,m,Us[500001],Vs[500001],t,w[500001],sta,k,ans,di

【强连通分量&#183;Tarjan】bzoj1179: [Apio2009]Atm

新博的第一发! 因为这几天切了几道强连通分量,所以从这里begin [题目描述] Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定,在每个路口都设立了一个Siruseri 银行的ATM 取款机.令人奇怪的是,Siruseri的酒吧也都设在路口,虽然并不是每个路口都设有酒吧.Banditji 计划实施Siruseri 有史以来最惊天动地的ATM 抢劫.他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的ATM 机,最终他将在一个酒吧庆祝他的胜利.使用高超的黑客技术,他获

bzoj 1179: [Apio2009]Atm【tarjan+spfa】

明明优化了spfa还是好慢-- 因为只能取一次值,所以先tarjan缩点,把一个scc的点权和加起来作为新点的点权,然后建立新图.在新图上跑spfa最长路,最后把酒吧点的dis取个max就是答案. #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const int N=500005,inf=1e9; int n,m,h[N],

缩点+spfa最长路【bzoj】 1179: [Apio2009]Atm

[bzoj] 1179: [Apio2009]Atm Description Siruseri 城中的道路都是单向的.不同的道路由路口连接.按照法律的规定, 在每个路口都设立了一个 Siruseri 银行的 ATM 取款机.令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧.Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫.他将从市中心 出发,沿着单向道路行驶,抢劫所有他 途径的 ATM 机,最终他将在一个酒吧庆 祝他的胜利.使用高超

tarjan+spfa最短路 BZOJ1179 [Apio2009] Atm

1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 3641  Solved: 1552[Submit][Status][Discuss] Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下

BZOJ1179 : [Apio2009]Atm 缩点+spfa

1179: [Apio2009]Atm Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2069  Solved: 826[Submit][Status][Discuss] Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来

bzoj1179: [Apio2009]Atm

tarjan缩点就是DAG上求最长路把...然而我并不会求...只会写spfa了... #include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<stack> #include<queue> using namespace std; #define rep(i,s,t) for(int i=s;i<=t;i++) #defin

【tarjan+拓扑】BZOJ3887-[Usaco2015 Jan]Grass Cownoisseur

[题目大意] 给一个有向图,然后选一条路径起点终点都为1的路径出来,有一次机会可以沿某条边逆方向走,问最多有多少个点可以被经过?(一个点在路径中无论出现多少正整数次对答案的贡献均为1) [思路] 首先缩点,对于每一个联通块求出正图和反图中节点1所在的联通块到它的最长节点数.这个用拓扑排序处理一下. 枚举每一条边取反,对于边(u,v),其取反后的距离就等于dis[u所在的联通快]+dis[v所在的联通块]-dis[1所在的联通块](因为会被重复计算不要忘记减去) 我一开始非常脑抽地在想会不会发生这