洛谷2656 采蘑菇

洛谷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
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  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]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) {
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 }

 

你可能感兴趣的:(洛谷2656 采蘑菇)