• 洛谷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<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
    ",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 }
  • 相关阅读:
    还零钱
    递归与动态规划II-汉诺塔
    leetcode 95. Unique Binary Search Trees II
    技术实力详解
    正反向路由
    usermod命令、用户密码管理、mkpasswd命令
    作为阿里的面试官,我有话想说。
    [招聘] 阿里巴巴-淘系技术部,长期内推,专人跟进。
    Vue源码翻译之渲染逻辑链
    Vue源码翻译之组件初始化。
  • 原文地址:https://www.cnblogs.com/lidaxin/p/4915368.html
Copyright © 2020-2023  润新知