洛谷2656 采蘑菇

来源:互联网 发布:mysql sql delete语句 编辑:程序博客网 时间:2024/05/16 23:02
洛谷2656 采蘑菇

本题地址: http://www.luogu.org/problem/show?pid=2656

题目描述

小胖和ZYR要去ESQMS森林采蘑菇。
     ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
     比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.
     现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。
     对于30%的数据,N<=7,M<=15
     另有30%的数据,满足所有“恢复系数”为0
     对于100%的数据,N<=80,000,M<=200,000,0.1<=恢复系数<=0.8且仅有一位小数,1<=S<=N.

输入输出格式

输入格式:

第一行,N和M
第2……M+1行,每行4个数字,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第M+2行,一个数字S

输出格式:

一个数字,表示最多能采到多少蘑菇,在int32范围内。

输入输出样例

输入样例#1:

3 3

1 2 4 0.5

1 3 7 0.1

2 3 4 0.6

1

输出样例#1:

8

【思路】

  强连通分量+最长路。

  Tarjan算法求SCC+缩点。SCC中的结点是可以互相到达的因此SCC内部的边权可以全部获得,将每条指向SCC的边权加上SCC的内部边权,再求一遍最长路即可。

  需要注意的有:

    1、记录f而不要将w提前分解成边。

    2、不要把大数组开在函数里面,否则会RE =-=。这点学了。

【代码】

 

  1 #include<cstdio>  2 #include<cstring>  3 #include<queue>  4 #include<stack>  5 #include<cmath>  6 #include<iostream>  7 using namespace std;  8   9 const int maxn = 80000+10,maxm=200000+10; 10 const int INF=1<<30; 11 struct Edge{ 12     int v,w,next; 13     double f; 14 }e[maxm]; 15 int en=-1,front[maxn]; 16  17 int n,m,s; 18  19 stack<int> S; 20 int scc_cnt,dfs_clock; 21 int sccno[maxn],pre[maxn],lowlink[maxn],scc_v[maxn]; 22 void dfs(int u) { 23     pre[u]=lowlink[u]=++dfs_clock; 24     S.push(u); 25     for(int i=front[u];i>=0;i=e[i].next){ 26         int v=e[i].v; 27         if(!pre[v]) { 28             dfs(v); 29             lowlink[u]=min(lowlink[u],lowlink[v]); 30         } 31         else if(!sccno[v]) { 32             lowlink[u]=min(lowlink[u],pre[v]); 33         } 34     } 35     if(lowlink[u]==pre[u]) 36     { 37        scc_cnt++; 38        for(;;) { 39            int v=S.top(); S.pop(); 40            sccno[v]=scc_cnt; 41            if(v==u) break; 42        } 43     } 44 } 45 void find_scc(int n) { 46     dfs_clock=scc_cnt=0; 47     memset(pre,0,sizeof(pre)); 48     memset(sccno,0,sizeof(sccno)); 49     for(int i=1;i<=n;i++) 50        if(!pre[i]) dfs(i); 51 } 52  53  54 inline void AddEdge(int u,int v,int w,double f) { 55     en++; e[en].v=v; e[en].w=w; e[en].f=f; e[en].next=front[u]; front[u]=en; 56 } 57  58 struct SPFA 59 { 60      Edge es[maxm]; 61      int esn,fr[maxn]; 62      int inq[maxn],d[maxn]; 63      queue<int> q; 64      int n; 65      void init(int n) { 66             this->n=n; esn=0; 67             memset(fr,-1,sizeof(fr)); 68      } 69      void addedge(int u,int v,int w) { 70             esn++; es[esn].v=v; es[esn].w=w; es[esn].next=fr[u]; fr[u]=esn; 71      } 72      void solve(int s) { 73          memset(inq,0,sizeof(inq)); 74          for(int i=1;i<=n;i++) d[i]=-INF; 75  76          d[s]=scc_v[s]; inq[s]=1; q.push(s); 77           while(!q.empty()) { 78              int u=q.front(); q.pop(); inq[u]=0; 79              for(int i=fr[u];i>=0;i=es[i].next) { 80                  int v=es[i].v,w=es[i].w; 81                  if(d[v]<d[u]+w) { 82                      d[v]=d[u]+w; 83                      if(!inq[v]) { 84                          inq[v]=1; 85                          q.push(v); 86                      } 87                  } 88              } 89         } 90         int ans=0; 91         for(int i=1;i<=n;i++) ans=max(ans,d[i]); 92         printf("%d\n",ans); 93     } 94 }; 95 SPFA spfa; 96  97 int main() { 98     memset(front,-1,sizeof(front)); 99     scanf("%d%d",&n,&m);100     int u,v,w; double f;101     for(int i=0;i<m;i++) {102         scanf("%d%d%d%lf",&u,&v,&w,&f);103         AddEdge(u,v,w,f);104     }105     scanf("%d",&s);106     find_scc(n);107     108     spfa.init(scc_cnt);109     110     for(int u=1;u<=n;u++) {111         for(int i=front[u];i>=0;i=e[i].next) {112             int v=e[i].v,w=e[i].w;113             double f=e[i].f;114             if(sccno[u]==sccno[v]) 115             {116                 scc_v[sccno[v]] += w; w=(int)(w*f);117                 while(w) {118                     scc_v[sccno[v]] += w;119                     w=(int)(w*f);120                 }121             }122         }123     }124     for(int u=1;u<=n;u++) {125         for(int i=front[u];i>=0;i=e[i].next) {126             int v=e[i].v,w=e[i].w;127             if(sccno[u]!=sccno[v]) {128                 w += scc_v[sccno[v]];    //sccno[v]129                 spfa.addedge(sccno[u],sccno[v],w);  //sccno[u]->sccno[v]130             }131         }132     }133     134     spfa.solve(sccno[s]);135     136     return 0;137 }

 

0 0