LUOGU P1453 城市环路(基环树+dp)
解题思路
一道基环树上$dp$的题,这种题比较套路吧,首先第一遍$dfs$把环找出来,然后对于环上的每一个点都向它子树内做一次树形$dp$,$f[i][0/1]$表示到了$i$这个点选或不选的最大值,转移和没有上司的舞会那道题差不多,就是求一个带权最大独立集。然后再在环上做一次树形$dp$,$g[i][0/1][0/1]$表示以$i$为根的子树中$i$选不选,最后一维记录的是起始节点选不选,因为终止节点和起始节点只能选一个,然后就胡乱$dp$一下。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<vector> using namespace std; const int MAXN = 100005; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,p[MAXN],head[MAXN],cnt,end; int to[MAXN<<1],nxt[MAXN<<1],stk[MAXN],top; double f[MAXN][2],ans,g[MAXN][2][2],k; bool vis[MAXN],b[MAXN],flag,in[MAXN]; vector<int> v; inline void add(int bg,int ed){ to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt; } void dfs(int x,int fa){ if(b[x]) { while(stk[top]!=x){ v.push_back(stk[top]); vis[stk[top]]=1;top--; } v.push_back(x); vis[x]=1;flag=1; return ; } b[x]=1;stk[++top]=x; for(register int i=head[x];i;i=nxt[i]){ int u=to[i];if(u==fa) continue; dfs(u,x);if(flag) return; top--;b[u]=0; } } void dp_l(int x,int fa){ f[x][1]=p[x]*k; for(register int i=head[x];i;i=nxt[i]){ int u=to[i];if(u==fa || vis[u]) continue; dp_l(u,x); f[x][1]+=f[u][0]; f[x][0]+=max(f[u][0],f[u][1]); } } void dp_h(int x,int fa){ for(register int i=head[x];i;i=nxt[i]){ int u=to[i];if(!vis[u] || u==fa) continue; if(in[u]) {end=x;g[x][0][0]=f[x][0];g[x][1][0]=f[x][1];return;} in[u]=1;dp_h(u,x); if(u==end) { g[x][0][1]=g[u][1][0]+f[x][0]; g[x][1][0]=g[u][0][0]+f[x][1]; g[x][0][0]=g[u][0][0]+f[x][0]; } else { g[x][0][1]=max(g[u][0][1],g[u][1][1])+f[x][0]; g[x][1][1]=g[u][0][1]+f[x][1]; g[x][0][0]=max(g[u][0][0],g[u][1][0])+f[x][0]; g[x][1][0]=g[u][0][0]+f[x][1]; } if(end) return; } } int main(){ n=rd();int x,y; for(int i=1;i<=n;i++) p[i]=rd(); for(int i=1;i<=n;i++){ x=rd()+1,y=rd()+1; add(x,y),add(y,x); } scanf("%lf",&k); dfs(1,0); vector<int>::iterator it=v.begin();int S=*it; for(;it<v.end();it++) dp_l(*it,0);in[S]=1; dp_h(S,0);ans=max(max(g[S][0][0],g[S][1][0]),g[S][0][1]); printf("%.1lf",ans); return 0; }