• 题解 CF25D 【Roads not only in Berland】


    咋一看是个图论,仔细一看其实是个并查集


    我们用并查集可以表示每个连通块,方法就是用并查集merge操作来加边,同时如果加边不成功,即两个端点已经在同一连通块内,那么把这个边加进回收站del[]数组,等到后面输出答案时,这个有着半壁江山。del[]数组的大小就是最好的方案数。

    然后我们扫描一遍并查集的f[]数组,统计连通块的个数(方法就是看有几个f[i]==i),连通块的个数后面要用。

    再说后面的方案输出,我们只要清空回收站,然后把各个连通块合并成一个,具体的话——看代码罢。

    代码在哪?就在下面

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define F first
    #define S second
    using namespace std;
    const int N=10005;
    int f[N],gr[N],n,tot,cnt,now;
    pair<int,int> d[N];
    int find(int x) {//并查集找祖宗
    	if(f[x]!=x) f[x]=find(f[x]);
    	return f[x];
    }
    bool merge(int x,int y) {//并查集合并
    	x=find(x);
    	y=find(y);
    	if(x!=y) f[x]=y;
    	else return 1;
    	return 0;
    }
    void del(int i) {//处理+输出函数
    	printf("%d %d %d %d
    ",d[i].F,d[i].S,gr[now],gr[cnt]);//输出回收站当前边、当前合并的连通块祖宗
    	merge(gr[now++],gr[cnt]);//合并连通块并将当前连通块定位到下一个
    }
    int main() {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) f[i]=i;
    	for(int i=1;i<n;i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		if(merge(x,y)) d[++tot]=make_pair(x,y);//扔进回收站
    	}
    	for(int i=1;i<=n;i++) if(f[i]==i) gr[++cnt]=i;//统计连通块的祖宗
    	now=1;
    	printf("%d
    ",tot);
    	for(int i=1;i<=cnt-1;i++)
    		del(i);//处理+输出
    	return 0;
    }
    
    
  • 相关阅读:
    纯CSS3实现3D动画导航,html5 webRTC技术实现免费网页电话拨打
    Base64编解码Android和ios的例子,补充JNI中的例子
    新春寄语
    彩票号码OC呈现
    iOS CFNetwork报错
    Android常用库
    高性能服务端访问设计
    Tomcat的ISO-8859-1
    迅达云s3cmd客户端mac平台部署说明
    Android.os.NetworkOnMainThreadException
  • 原文地址:https://www.cnblogs.com/ahawzlc/p/12845009.html
Copyright © 2020-2023  润新知