洛谷 P2656 采蘑菇(Tarjan缩点,dp)

传送门


解题思路

对于每一条路,很显然只有两种情况,一种是走一次,一种是走无限次,而第二种情况的条件是这条边在一个环中。

所以先用Tarjan缩点,每个点的权值更新为这个环上所有边一直摘的蘑菇数的和。

然后跑一边既有边权也有点权的DAG上的dp即可。

//数据有锅,后四个点答案有误,用double存实际上错了,但是标程是double,为了过题只能改成double了。

具体原因请看这篇博客:关于float、double小项问题

AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<stack>
 7 using namespace std;
 8 const int maxn=80008;
 9 const int maxm=200005;
10 int n,m,scc_cnt,cnt,p[maxn][2],dp[maxn],w[maxn];
11 int sscc[maxn],dfn[maxn],low[maxn],times,num[maxn],ss;
12 stack<int> s;
13 struct node{
14     int v,next,value,sum;
15 }e[maxm][2];
16 void insert(int u,int v,int value,int sum,int id){
17     cnt++;
18     e[cnt][id].v=v;
19     e[cnt][id].value=value;
20     e[cnt][id].sum=sum;
21     e[cnt][id].next=p[u][id];
22     p[u][id]=cnt;
23 }
24 void dfs(int u){
25     dfn[u]=low[u]=++times;
26     s.push(u);
27     for(int i=p[u][0];i!=-1;i=e[i][0].next){
28         int v=e[i][0].v;
29         if(!dfn[v]){
30             dfs(v);
31             low[u]=min(low[u],low[v]);
32         }else if(num[v]==0){
33             low[u]=min(low[u],dfn[v]);
34         }
35     }
36     if(dfn[u]==low[u]){
37         ++scc_cnt;
38         while(1){
39             int x=s.top();
40             s.pop();
41             num[x]=scc_cnt;
42             if(x==u) break;
43         }
44     }
45 }
46 void dfs2(int u){
47     if(dp[u]) return;
48     dp[u]=sscc[u];
49     for(int i=p[u][1];i!=-1;i=e[i][1].next){
50         int v=e[i][1].v;
51         dfs2(v);
52         dp[u]=max(dp[u],dp[v]+e[i][1].value+sscc[u]);
53     }
54 }
55 int main()
56 {
57     memset(p,-1,sizeof(p));
58     cin>>n>>m;
59     for(int i=1;i<=m;i++){
60         int u,v,value,sum=0;
61         double p;
62         scanf("%d%d%d%lf",&u,&v,&value,&p);
63         int vv=value;
64         while(value>0){
65             sum+=value;
66             value=floor((double)value*p); 
67         }
68         insert(u,v,vv,sum,0);
69     }
70     cin>>ss;
71     for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
72     cnt=0;
73     for(int u=1;u<=n;u++){
74         for(int i=p[u][0];i!=-1;i=e[i][0].next){
75             int v=e[i][0].v;
76             if(num[u]==num[v]){
77                 sscc[num[u]]+=e[i][0].sum;
78             }else{
79                 insert(num[u],num[v],e[i][0].value,0,1);
80             }
81         }
82     }
83     dfs2(num[ss]);
84     cout<<dp[num[ss]];
85     return 0;
86 }

 

posted @ 2020-10-23 21:06  尹昱钦  阅读(132)  评论(0编辑  收藏  举报