重修 基环树

P1453 城市环路

求一棵基环树中独立集点权和最大值

我的辣鸡写法(考场上没调出来、家里写 3 hours)

topo 找基环,对于每个环上的点,作为 root 树形 DP,再在环上环形 DP 即可

#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define For(i,j,k) for(register int i=j;i<=k;i++)
#define N 100010
vector<int> e[N],cy;
int clen;
int a[N];
int deg[N];
bool vis[N];
int dp[N][2];//树上 DP
int f[N][2][2];//环上 DP
int n;
double k;
void topo(){
queue<int> q;
For(i,0,n-1){
if(deg[i]==1){
q.push(i);
vis[i]=1;
}
}
int now;
while(!q.empty()){
now=q.front();
q.pop();
for(int i:e[now]){
if(vis[i]) continue;
deg[i]--;
if(deg[i]==1){
q.push(i);
vis[i]=1;
}
}
}
now=0;
while(vis[now])now++;
while(!vis[now]){
vis[now]=1;
cy.pb(now);
for(int i:e[now]){
if(!vis[i]){
now=i;
break;
}
}
}
clen=cy.size();
}
void dfs(int rt,int fa,int b1,int b2){
dp[rt][0]=0;
dp[rt][1]=a[rt];
for(int i:e[rt]){
if(i==fa || i==b1 || i==b2) continue;
dfs(i,rt,b1,b2);
dp[rt][0]+=max(dp[i][0],dp[i][1]);
dp[rt][1]+=dp[i][0];
}
}
void DP(){
For(i,0,clen-1){
dfs(cy[i],-1,cy[(i+clen-1)%clen],cy[(i+1)%clen]);
// cerr<<cy[i]<<":"<<dp[cy[i]][0]<<" "<<dp[cy[i]][1]<<endl;
}
f[0][0][0]=dp[cy[0]][0];
f[0][1][1]=dp[cy[0]][1];
For(i,1,clen-1) For(j,0,1){
f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1])+dp[cy[i]][0];
f[i][j][1]=f[i-1][j][0]+dp[cy[i]][1];
}
}
signed main(){
scanf("%d",&n);
For(i,0,n-1) scanf("%d",a+i);
int x,y;
For(i,0,n-1){
scanf("%d%d",&x,&y);
e[x].pb(y);
e[y].pb(x);
deg[x]++;
deg[y]++;
}
scanf("%lf",&k);
topo();
// cerr<<"cy:"; for(int i:cy) cerr<<i<<" "; cerr<<endl;
DP();
int ans=max(f[clen-1][0][0],max(f[clen-1][1][0],f[clen-1][0][1]));
printf("%.1lf\n",ans*k);
return 0;
}

简便写法

随便断基环上任意一条边 (x,y),图就变成了一棵树,以 x 为根不能取 x 的独立集更新一下 Ans,再以 y 为根不能取 y 的独立集更新一下 Ans,答案就出来了。

#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define For(i,j,k) for(register int i=j;i<=k;i++)
#define ckmx(a,b) if(a<b){a=b;}
#define N 100010
int n,a[N],f[N],S,T,dp[N][2];
vector<int> e[N];
double k;
inline int gf(int x){ return f[x]==x?x:f[x]=gf(f[x]); }
void dfs(int rt,int fa){
// cerr<<rt<<" "<<fa<<endl;
dp[rt][0]=0;
dp[rt][1]=a[rt];
for(int i:e[rt]){
if(i==fa) continue;
dfs(i,rt);
dp[rt][0]+=max(dp[i][0],dp[i][1]);
dp[rt][1]+=dp[i][0];
}
// cerr<<rt<<" "<<dp[rt][0]<<" "<<dp[rt][1]<<endl;
}
signed main(){
scanf("%d",&n);
For(i,0,n-1) f[i]=i;
For(i,0,n-1) scanf("%d",a+i);
int x,y;
For(i,0,n-1){
scanf("%d%d",&x,&y);
if(gf(x)==gf(y)){
S=x;
T=y;
}else{
e[x].pb(y);
e[y].pb(x);
f[gf(x)]=gf(y);
}
}
scanf("%lf",&k);
int ans=0;
dfs(S,-1);
ckmx(ans,dp[S][0]);
dfs(T,-1);
ckmx(ans,dp[T][0]);
printf("%.1lf\n",ans*k);
return 0;
}
posted @   ShaoJia  阅读(68)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示