CF720B 解题报告

题目大意

给定一个仙人掌,每条边有颜色,求将原仙人掌断边成树后边权最多有多少不同的。

解题报告

仙人掌有性质为:一条边不会在多个环内。意味着各个环的操作是独立的。考虑统计所有环上的颜色和数量,此部分易实现。

最大化颜色种类数,等价于最小化所失去的颜色数量。
易转化成强制无法删除所有种类颜色,最终剩余几个环无法删除即为要删除多少的颜色。

该部分有若干限制,控制了每种颜色最多用多少,每个环只能删除一个,观察数据范围不超过 \(1e4\),考虑用网络流解决问题。

\(S,T\) 为超源和超汇,该模型较为简单,考虑直接建出。

  • \(S\to i\ 连一条容量为 \ all_i-1\ 的边,\\ 表示一共只能删除\ all_i-1\ 条颜色 \ i\ 的边,其中 \ i\ 为颜色\ i\ ,\ all_i\ 为环上边颜色为 \ i\ 的数量\\ (若颜色 \ i\ 有非环边,则容量为 \ all_i\ )\)

  • \(i\to i'连一条容量为1的边,表示每个环只能删除环内颜色的一条边,其中i'为第i'个环\)

  • \(i'\to T\ 连一条容量为1的边,表示一个集合最多删除一条边\)

那么最后求出的最大流即为在不删除颜色的前提下每个环删除一条边的最大环数,则要删除的颜色数即为环的总数量-最大流。

代码

写的好丑

void add(int x,int y,int c){
	to[++idx]=y,from[idx]=x,col[idx]=c,ne[idx]=h[x],h[x]=idx;
}

void dfs(int u,int par){
	dfn[u]=++ti;
	for(int i=h[u];i;i=ne[i]){
		int v=to[i];
		if(v==par) continue;
		if(!dfn[v]){			 
			sta[++top]=i;
			dfs(v,u);
		}
		if(dfn[v]<dfn[u]){
			++tot;
			cnt[tot][col[i]]++;
			vis[i]=vis[i^1]=1;		
			while(from[sta[top]]!=v&&top){
				cnt[tot][col[sta[top]]]++;
				vis[sta[top]]=1;
				vis[sta[top]^1]=1;
				top--;
			}
			vis[sta[top]]=1;
			vis[sta[top]^1]=1;
			cnt[tot][col[sta[top]]]++;
			top--;
		}
		if(sta[top]==i) top--;
	}
}

int all[N],S,T,col_id[N],cur[N],dis[N];

void add_edge(int u,int v,int c){
	to[++idx]=v,cap[idx]=c,ne[idx]=h[u],h[u]=idx;
	to[++idx]=u,cap[idx]=0,ne[idx]=h[v],h[v]=idx;
}

void bfs(){
	memset(dis,-1,sizeof dis);
	queue <int> q;
	q.push(S),dis[S]=0;
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=h[u];i;i=ne[i]){
			int v=to[i];
			if(!cap[i]) continue;
			if(!~dis[v]){
				dis[v]=dis[u]+1;
				q.push(v);
			}
		}
	}
}

int DFS(int u,int f){
	if(u==T) return f;
	int tmp=f;
	for(int i=h[u];i;i=ne[i]){
		if(!cap[i]||dis[to[i]]!=dis[u]+1)
			continue;
		int d=DFS(to[i],min(cap[i],f));
		if(d){
			cap[i]-=d,cap[i^1]+=d;
			tmp-=d;
			if(!tmp) break;
		}
		else dis[to[i]]=0;
	}
	return f-tmp;
}

int dinic(){
	int res=0;
	while(1){
		bfs();
		if(!~dis[T]) break;
		res+=DFS(S,2e9);
	}
	return res;
}

void Main(){
//	memset(h,-1,sizeof h);
	n=rd,m=rd;
	int col_all_cnt=0;
	for(int i=1;i<=m;i++){
		int u=rd,v=rd,w=rd;
		if(!no[w]) no[w]=1,col_all_cnt++;
		add(u,v,w),add(v,u,w);
	}
	dfs(1,-1);
	memset(no,0,sizeof no);
	for(int i=2;i<=idx;i++){
		if(vis[i]) continue;
		no[col[i]]=1;
	}
	memset(h,0,sizeof h),idx=1;
	for(int i=1;i<=tot;i++){
		for(auto it:cnt[i])
			all[it.first]+=it.second;
	}
	S=0,T=1,ti=1;
	for(int i=1;i<=m;i++)
		if(all[i])
			col_id[i]=++ti,add_edge(S,ti,all[i]-(!no[i]));
	for(int i=1;i<=m;i++)
		if(!col_id[i])
			col_id[i]=++ti;	
	for(int i=1;i<=tot;i++){
		++ti;
		for(auto it:cnt[i])
			add_edge(col_id[it.first],ti,1);
		add_edge(ti,T,1);
	}
	cout<<col_all_cnt-(tot-dinic())<<endl;
}
posted @ 2024-06-01 19:29  SmileMask  阅读(7)  评论(0编辑  收藏  举报