洛谷P1453 城市環路
阿新 • • 發佈:2022-04-15
這道題的解題關鍵在於:n個點,n條邊
說起n個點,n-1條邊,聯通,必然是樹形結構
那再多一條邊呢?
這種圖有自己的名字:基環樹,也就是隻有一個環的樹
比如:
在做這題前可以先去看看:洛谷P1352沒有上司的舞會
要求一條邊的兩個端點不能同時取,處理方法是設dp[i][0/1]表示這點取或者不取
轉移方程為:
dp[u][0]+=max(dp[to][0],dp[to][1]); dp[u][1]+=dp[to][0];
其中該點不選(0)時,對son沒有影響,貪心地選擇最大值即可;
該點要選(1)時,要求son一定不能選,就只能+dp[son][0];
這道題可以看成是基環樹版本的P1352
做法是分別找環上兩點S和T,以這兩點為根進行一次dfs,最後取dp[S][0]和dp[T][0]的最大值
因為狀態轉移方程可以保證樹的兩邊點不能同時選,但無法保證S和T有沒有同時選,這個dp過程是不知道的
假設最優解為選S,不選T,那麼答案在dp[T][0],同理dp[S][0]
如果最優解是S和T都不選,那更好了>_<
PS:對於基環樹,一般可以刪去一條邊,轉化為比較熟悉的樹,或者像這題這樣什麼的
#include<bits/stdc++.h> using namespace std; const int maxn=int(1e5)+7; int vis[maxn],vis2[maxn],n,p[maxn],head[maxn],cnt=0,s,t,isfind=0; long long ans=0,dp[maxn][3],dp2[maxn][3]; double k; struct lys{ int from,to,nxt; }e[maxn*3]; void add(int from,int to) { cnt++;e[cnt].from=from;e[cnt].to=to;e[cnt].nxt=head[from];head[from]=cnt; } void build(int fa,int u) { vis[u]=1; for(int i=head[u];i;i=e[i].nxt) {int to=e[i].to; if(to==fa) continue; if(vis[to]==1) { s=to;t=u;continue; } build(u,to); } } void dfs(int fa,int u) { vis[u]=1; dp[u][0]=0; dp[u][1]=p[u]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa||vis[to]) continue; dfs(u,to); dp[u][0]+=max(dp[to][0],dp[to][1]); dp[u][1]+=dp[to][0]; } } int main() { isfind=0; //freopen("lys.in","r",stdin); cin>>n; for(int i=1;i<=n;i++) cin>>p[i]; for(int i=1;i<=n;i++) { int u,v;cin>>u>>v; u++;v++; add(u,v); add(v,u); } cin>>k; build(-1,1); memset(vis,0,sizeof(vis)); dfs(0,s); ans=dp[s][0]; memset(vis,0,sizeof(vis)); dfs(0,t); ans=max(dp[s][0],dp[t][0]); printf("%.1lf",(double)ans*k); }