Luogu P1453 城市環路
阿新 • • 發佈:2018-12-02
這是一道基環樹上DP的裸題
沒有上司的舞會想必大家都A掉了
這題只不過是在那個基礎上套上一個環
按照基環樹的解決套路,找到環後斷掉一條邊,或者先對環上的結點進行一遍樹形DP,然後再進行一遍環形DP
這題我選了後者
dfs1求環,dfs樹形DP,再列舉環上第一個點選不選進行環上DP就可以了
#include<cstdio> #include<iostream> using namespace std; const int N=1e6+5; int n,st[N],top,num,b[N],f[N][2],g[N][2],a[N],ans; int to[N],nxt[N],cnt,he[N]; bool fl[N]; double k; inline void add(int u,int v) { to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt; } void dfs1(int u,int fa) { fl[u]=1; st[++top]=u; for(int e=he[u];e;e=nxt[e]) { int v=to[e]; if(v==fa) continue; if(fl[v]) { b[++num]=v; while(top&&st[top]!=v) b[++num]=st[top--]; }else dfs1(v,u); if(num) return; } top--; } void dfs(int u,int fa,int jj1,int jj2) { f[u][1]=a[u]; for(int e=he[u];e;e=nxt[e]) { int v=to[e]; if(v!=fa&&v!=jj1&&v!=jj2) { dfs(v,u,jj1,jj2); f[u][0]+=max(f[v][1],f[v][0]); f[u][1]+=f[v][0]; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int u,v; scanf("%d%d",&u,&v); u++,v++; add(u,v),add(v,u); } scanf("%lf",&k); dfs1(1,0); for(int i=1;i<=num;i++) dfs(b[i],0,(i==1)?b[num]:b[i-1],(i==num)?b[1]:b[i+1]); g[1][0]=f[b[1]][0],g[1][1]=0; for(int i=2;i<=num;i++) { g[i][0]=max(g[i-1][0],g[i-1][1])+f[b[i]][0]; g[i][1]=g[i-1][0]+f[b[i]][1]; } ans=max(g[num][1],g[num][0]); for(int i=1;i<=num;i++) g[i][0]=g[i][1]=0; g[1][0]=0,g[1][1]=f[b[1]][1]; for(int i=2;i<=num;i++) { g[i][0]=max(g[i-1][0],g[i-1][1])+f[b[i]][0]; g[i][1]=g[i-1][0]+f[b[i]][1]; } ans=max(ans,g[num][0]); k*=ans; printf("%.1lf",k); return 0; }