P2656 采蘑菇 tarjan + spfa

模板题

链接:https://www.luogu.org/problem/show?pid=2656

对于每条路,能多采就多采

每条路都有恢复系数

所以走完一遍仍然可以回来再采(如果有路)

显然要处理出环里的能采的最大值

处理成点权吧

然后缩成DAG

发现我可以跑最长路了

这题就是这样~

(这是学缩点的模板题QAQ)

更详细的解释:http://blog.csdn.net/loi_xczhw/article/details/49406781   //(2333学长博客)

Codes:

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<stack>
  6 using namespace std;
  7 const int N = 200000 + 5;
  8 const int N1 = 100000 + 5;
  9 int n,m,head[N],nxt[N << 1],cnt,ff[N],tt[N],vv[N],S;
 10 int scc[N],val[N],dis[N],dfn_c,dfn[N],low[N],huan_c,ans = -1;
 11 double re[N];
 12 struct Edge{
 13     int ff,tt,vv;
 14     double re;
 15 }edge[N << 1];
 16 void build(int f,int t,int v,double rec){
 17     edge[++ cnt] = (Edge){f,t,v,rec};
 18     nxt[cnt] = head[f];
 19     head[f] = cnt;
 20     return;
 21 }
 22 void clear(){
 23     memset(head,0,sizeof(head));
 24     memset(nxt,0,sizeof(nxt));
 25     cnt = 0;
 26     return;
 27 }
 28 stack <int> s;
 29 void dfs(int x){
 30     s.push(x);
 31     dfn[x] = low[x] = ++ dfn_c;
 32     for(int i = head[x];i;i = nxt[i]){
 33         int t = edge[i].tt;
 34         if(!dfn[t]){
 35             dfs(t);
 36             low[x] = min(low[t],low[x]);
 37         }
 38         else if(!scc[t]){
 39             low[x] = min(low[x],dfn[t]);//关于这里是和low[t]还是dfn[t]取min好像是都可以
 40         }                 //因为只要Low[x] != dfn[x] 即可,low[x]更新成什么不重要
 41     }                     //你非要卡着dfn定义去理解也可以~
 42     if(dfn[x] == low[x]){
 43         ++ huan_c;
 44         int tot = 0;
 45         while(1){
 46             int u = s.top();
 47             s.pop();
 48             scc[u] = huan_c;
 49             if(u == x) break;
 50         }
 51     }
 52     return;
 53 }
 54 bool vis[N1];
 55 int get_val(int i){
 56     int v = edge[i].vv;
 57     int ans = v;
 58     while(v){
 59         v *= edge[i].re;
 60         ans += v;
 61     }
 62     return ans;
 63 }
 64 deque <int> q;
 65 void spfa(int x){ //最长路 
 66     memset(dis,0x80,sizeof(dis));//2139062144
 67     while(!q.empty()) q.pop_front();
 68     dis[x] = val[x];
 69     q.push_back(x);
 70     q.push_back(80001);
 71     vis[x] = 1;
 72     while(!q.empty()){
 73         int u = q.front();
 74         q.pop_front();
 75         vis[u] = 0;
 76         for(int i = head[u];i;i = nxt[i]){
 77             int t = edge[i].tt;
 78             int v = edge[i].vv;
 79             if(dis[t] < dis[u] + v + val[t]){ //考虑点权 
 80                 dis[t] = dis[u] + v + val[t];
 81                 if(vis[t]) 
 82                     continue;
 83                 if(!q.empty() && dis[t] > dis[q.front()])
 84                     q.push_front(t);
 85                 else if(!q.empty())
 86                     q.push_back(t);
 87                 vis[t] = 1;
 88             }
 89         }
 90     }
 91     return;
 92 }
 93 void buildd(){
 94     for(int i = 1;i <= n;++ i){
 95         for(int j = head[i];j;j = nxt[j]){
 96             int t = tt[j];
 97             if(scc[i] == scc[t]){
 98                 val[scc[i]] += get_val(j); //点权 
 99             }
100         }
101     }
102     clear();
103     for(int i = 1;i <= m;++ i){
104         int f = ff[i],t = tt[i];
105         if(scc[f] != scc[t]){
106             build(scc[f],scc[t],vv[i],re[i]);//缩点重建 
107         }
108     }
109 }
110 void work(){
111     buildd(); //缩点 
112     spfa(scc[S]);
113     for(int i = 1;i <= n;++ i){
114         ans = max(ans,dis[i]); // 求最长路 
115     }
116     cout << ans << '
';
117 }
118 int main(){
119 //    freopen("mushroom1.in","r",stdin);
120 //    freopen("mushroom1.out","w",stdout);
121     scanf("%d%d",&n,&m);
122     for(int i = 1;i <= m;++ i){
123         scanf("%d%d%d%lf",&ff[i],&tt[i],&vv[i],&re[i]);
124         build(ff[i],tt[i],vv[i],re[i]);
125     }
126     scanf("%d",&S);
127     dfs(S);
128     work();
129     return 0;
130 }

 

原文地址:https://www.cnblogs.com/Loizbq/p/7685032.html