重修 基环树

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 @ 2021-10-10 21:38  ShaoJia  阅读(61)  评论(0编辑  收藏  举报