洛谷 P1453 城市環路(基環樹,樹形dp)
阿新 • • 發佈:2021-10-25
傳送門
解題思路
先找到基環樹上的環,然後斷掉任意一條環上的邊,分別以兩個端點做樹形dp(沒有上司的舞會),最後答案就是max(dp1[s][0],dp2[t][0])。
其中dp1[s][0]為以s為根節點不選s的答案,dp2[t][0]表示以t為根節點不選t時的答案。
AC程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<map> #include<vector> #include<iomanip> using namespace std; const int maxn=1e5+5; int p[maxn],cnt,a[maxn],in[maxn],s,t,n; double k; long long ans,dp[maxn][2]; struct node{ int v,next; }e[maxn*2]; void insert(int u,int v){ cnt++; e[cnt].v=v; e[cnt].next=p[u]; p[u]=cnt; } void topo(){ queue<int> q; for(int i=1;i<=n;i++){ if(in[i]==1) q.push(i),in[i]--; } while(!q.empty()){ int u=q.front();q.pop(); for(int i=p[u];i!=-1;i=e[i].next){ int v=e[i].v; in[v]--; if(in[v]==1) q.push(v); } } } void dfs(int u,int fa){ dp[u][1]=a[u]; for(int i=p[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v==fa||(s==u&&t==v)||(s==v&&t==u)) continue; dfs(v,u); dp[u][0]+=max(dp[v][1],dp[v][0]); dp[u][1]+=dp[v][0]; } } int main(){ ios::sync_with_stdio(false); memset(p,-1,sizeof(p)); cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++){ int u,v; cin>>u>>v; u++;v++; insert(u,v); insert(v,u); in[v]++;in[u]++; } cin>>k; topo(); for(int u=1;u<=n;u++){ if(s&&t) break; if(in[u]>=2){ for(int i=p[u];i!=-1;i=e[i].next){ int v=e[i].v; if(in[v]==2){ s=u,t=v; break; } } } } dfs(s,-1); ans=dp[s][0]; memset(dp,0,sizeof(dp)); dfs(t,-1); ans=max(ans,dp[t][0]); cout<<fixed<<setprecision(1)<<k*ans; return 0; }