• [Luogu2656]采蘑菇


    题目大意:
      给你一个有向图,每条边有一个边权w以及恢复系数k,
      你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整。
      问你最大能获得的收益为多少?

    思路:
      缩点+DP。
      首先跑一下Tarjan(只要从s开始跑,因为没跑到的地方肯定和答案没关系)。
      对于每个强连通分量,我们算一下经过这个强联通分量能获得的总收益sum(就是拼命在这上面绕圈圈)。
      把原图缩为一个DAG,然后就可以DP了。
      设当前点为i,后继结点为j,边权为w,j的SCC的总收益为sum[j],转移方程为f[j]=max{f[i]+w+sum[j]}。
      当然也只要从s开始DP即可。

      1 #include<cmath>
      2 #include<stack>
      3 #include<queue>
      4 #include<cstdio>
      5 #include<cctype>
      6 #include<vector>
      7 #include<cstring>
      8 inline int getint() {
      9     register char ch;
     10     while(!isdigit(ch=getchar()));
     11     register int x=ch^'0';
     12     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     13     return x;
     14 }
     15 const int N=80001,M=200000;
     16 struct Edge {
     17     int from,to,w;
     18     double k;
     19     int next;
     20 };
     21 Edge e[M];
     22 int head[N];
     23 inline void add_edge(const int &u,const int &v,const int &w,const double &k,const int &i) {
     24     e[i]=(Edge){u,v,w,k,head[u]};
     25     head[u]=i;
     26 }
     27 int s;
     28 int dfn[N],low[N],scc[N],cnt,id,sum[N],in[N];
     29 bool ins[N];
     30 std::stack<int> stack;
     31 void tarjan(const int &x) {
     32     dfn[x]=low[x]=++cnt;
     33     stack.push(x);
     34     ins[x]=true;
     35     for(int i=head[x];~i;i=e[i].next) {
     36         const int &y=e[i].to;
     37         if(!dfn[y]) {
     38             tarjan(y);
     39             low[x]=std::min(low[x],low[y]);
     40         } else if(ins[y]) {
     41             low[x]=std::min(low[x],dfn[y]);
     42         }
     43     }
     44     if(dfn[x]==low[x]) {
     45         id++;
     46         int y=0;
     47         while(y!=x) {
     48             y=stack.top();
     49             stack.pop();
     50             ins[y]=false;
     51             scc[y]=id;
     52         }
     53     }
     54 }
     55 int ans,f[N];
     56 std::queue<int> q;
     57 inline void dp() {
     58     q.push(scc[s]);
     59     f[scc[s]]=sum[scc[s]];
     60     while(!q.empty()) {
     61         const int x=q.front();
     62         q.pop();
     63         ans=std::max(ans,f[x]);
     64         for(register int i=head[x];~i;i=e[i].next) {
     65             const int &y=e[i].to;
     66             f[y]=std::max(f[y],f[x]+e[i].w+sum[y]);
     67             if(!--in[y]) q.push(y);
     68         }
     69     }
     70 }
     71 int main() {
     72     const int n=getint(),m=getint();
     73     memset(head,-1,sizeof head);
     74     for(register int i=0;i<m;i++) {
     75         const int u=getint(),v=getint(),w=getint();
     76         double k;
     77         scanf("%lf",&k);
     78         add_edge(u,v,w,k,i);
     79     }
     80     s=getint();
     81     tarjan(s);
     82     memset(head,-1,sizeof head);
     83     for(register int i=0;i<m;i++) {
     84         const int &u=e[i].from,&v=e[i].to;
     85         if(!dfn[u]||!dfn[v]) continue; 
     86         if(scc[u]==scc[v]) {
     87             const double &k=e[i].k;
     88             int w=e[i].w;
     89             while(w>0) {
     90                 sum[scc[u]]+=w;
     91                 w=floor(w*k);
     92             }
     93         } else {
     94             in[scc[v]]++;
     95             add_edge(scc[u],scc[v],e[i].w,e[i].k,i);
     96         }
     97     }
     98     dp();
     99     printf("%d
    ",ans);
    100     return 0;
    101 }
  • 相关阅读:
    codeforces 169 div2 C
    poj 1062(最短路)
    sgu 118
    sgu 101
    poj 2446二分图匹配
    ural 1129 (求数据)
    C#中抽象类和接口的区别(转)
    在.net(C# or vb.net)中,Appplication.Exit 还是 Form.Close有什么不同?
    一道爱出的题目,就是前面两个数相加 用递归方法实现
    C#冒泡排序
  • 原文地址:https://www.cnblogs.com/skylee03/p/7773257.html
Copyright © 2020-2023  润新知