zoukankan      html  css  js  c++  java
  • 题解 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;
    }
    
    
  • 相关阅读:
    个人7天安排
    七天安排
    京东搜索规则
    关于从一个整数数组中求得最大的子整数组和
    结对项目开发--电梯调度
    分析英文文本各个词出现的频率
    关于安卓版的eclipse连接数据库并誓言增删改查
    电梯调度 结对开发项目
    求一个二维数组的最大子数组
    求一堆数组中最大的子数组
  • 原文地址:https://www.cnblogs.com/ahawzlc/p/12845009.html
Copyright © 2011-2022 走看看