1. 程式人生 > >[Luogu2656]采蘑菇

[Luogu2656]采蘑菇

clas ble struct size 出發 sdi ans () cnblogs

題目大意:
  給你一個有向圖,每條邊有一個邊權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\n",ans); 100 return 0; 101 }

[Luogu2656]采蘑菇