重修 基环树
即求一棵基环树中独立集点权和最大值。
我的辣鸡写法(考场上没调出来、家里写 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;
}
本文来自博客园,作者:ShaoJia,版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。