BZOJ1815: [Shoi2006]color 有色图 群论+Polya定理+组合数学
3526: [Poi2014]Card 线段树

BZOJ3624: [Apio2008]免费道路 Kruskal+构造

shinbokuow posted @ Sep 05, 2015 03:56:55 PM in BZOJ with tags 构造 Kruskal , 1324 阅读

 

题解:

呵,不要欺骗我的感情好么?

明明半年之前我还会做这道题呢。。。

算了闲话少说,进入正题。

题目中的边分为两种,我们要构造出一颗生成树使得两种边的个数均符合要求。

考虑优先加入a类边以及优先加入b类边,这样就能得出合法生成树中a类边个数的上界和下界。

事实上,上下界区间中的任何一个值都是能够取到的。

我们考虑这样构造合法的生成树:考虑优先加入b类边,这样就能得到一些必须加入的a类边。

将加入的所有b类边删除,加入一些刚才没有加入的a类边(在此过程中不能产生环)直到a类边个数恰好等于要求。

再加入所有b类边直到形成一颗完整的生成树。

只要边数在区间中则一定能够构造出来。

就按照这种方法构造就行了。

代码:

 

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

#define N 20010
#define M 100010
int n,m,k;

struct Edge{
	int a,b;
	Edge(){}
	Edge(int _a,int _b):a(_a),b(_b){}
};
vector<Edge>A,B,C;

int r[N],siz[N];
inline int find(int x){
	return x==r[x]?x:r[x]=find(r[x]);
}
inline void merge(int ra,int rb){
	if(siz[ra]>siz[rb])
		swap(ra,rb);
	siz[rb]+=siz[ra];
	r[ra]=rb;
}

int a[M],b[M],c[M];

inline int getc(){
	static const int L=1<<15;
	static char buf[L],*S=buf,*T=buf;
	if(S==T){
		T=(S=buf)+fread(buf,1,L,stdin);
		if(S==T)
			return EOF;
	}
	return*S++;
}
inline int getint(){
	int c;
	while(!isdigit(c=getc()));
	int x=c-'0';
	while(isdigit(c=getc()))
		x=(x<<1)+(x<<3)+c-'0';
	return x;
}

inline int solve(vector<Edge>&s){
	int i,j,ra,rb,ans=0;
	for(i=1;i<=n;++i)
		r[i]=i,siz[i]=1;
	for(i=0;i<s.size();++i){
		ra=find(s[i].a);
		rb=find(s[i].b);
		if(ra!=rb){
			++ans;
			merge(ra,rb);
		}
	}
	return ans;
}

bool ok[M];

int main(){
#ifndef ONLINE_JUDGE
	freopen("tt.in","r",stdin);
#endif
	n=getint(),m=getint(),k=getint();
	int i,j;
	for(i=1;i<=m;++i){
		a[i]=getint();
		b[i]=getint();
		c[i]=getint();
		C.push_back(Edge(a[i],b[i]));
		if(c[i]==0)
			A.push_back(Edge(a[i],b[i]));
		else
			B.push_back(Edge(a[i],b[i]));
	}
	int ansa=solve(A);
	int ansc=solve(C);
	int ansb=solve(B);
	if(ansc!=n-1||k<n-1-ansb||k>ansa)
		puts("no solution");
	else{
		int ra,rb,edge=0;
		for(i=1;i<=m;++i){
			if(c[i]==0){
				ra=find(a[i]),rb=find(b[i]);
				if(ra!=rb){
					ok[i]=1;
					++edge;
					merge(ra,rb);
				}
			}
		}
		for(i=1;i<=n;++i)
			r[i]=i,siz[i]=1;
		for(i=1;i<=m;++i)
			if(ok[i]){
				ra=find(a[i]),rb=find(b[i]);
				if(ra!=rb)
					merge(ra,rb);
			}
		for(i=1;i<=m;++i)
			if(c[i]==0&&!ok[i]){
				ra=find(a[i]),rb=find(b[i]);
				if(ra!=rb&&edge<k){
					ok[i]=1;
					++edge;
					merge(ra,rb);
				}
			}
		for(i=1;i<=m;++i)
			if(c[i]){
				ra=find(a[i]),rb=find(b[i]);
				if(ra!=rb){
					ok[i]=1;
					merge(ra,rb);
				}
			}
		for(i=1;i<=m;++i)
			if(ok[i])
				printf("%d %d %d\n",a[i],b[i],c[i]);
	}
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter