!并查集未完待续!|图的遍历/并查集--连通块数dfs|1013 Battle Over Cities (25分)

很类似的
模块
link

vector<int>G[1010];    
for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;//--------写到这,手又忍不住要写Union(a,b)了- -,无语
        G[a].push_back(b);//建立关系
        G[b].push_back(a);
    }

搜联通块搜到当前访问的顶点编号是删除的城市编号,就退出,此连通块遍历结束
继续下一个连通块的遍历
在这里插入图片描述

 for(int j=1;j<=n;j++){//The cities are numbered from 1 to N.
            if(j!=city&&vis[j]==false){//不是被删除并且没被访问过的城市//遍历不是删除城市的顶点
                dfs(j);//遍历顶点i所在的连通块,depth没用,就没写//写到这,又想写if条件,重新init(),Union(),计算联通块数了
                cnt++;
            }
        }
    for(int i=0;i<q;i++){
        cin>>city;
        memset(vis,false,sizeof(vis));//恢复原状
        int cnt=0;
        //1 2 3//如何求1.多个2.没有某个顶点的图的联通块数?//
        for(int j=1;j<=n;j++){//The cities are numbered from 1 to N.
            if(j!=city&&vis[j]==false){//不是被删除并且没被访问过的城市//遍历不是删除城市的顶点
                dfs(j);//遍历顶点i所在的连通块,depth没用,就没写//写到这,又想写if条件,重新init(),Union(),计算联通块数了
                cnt++;
            }
        }
         cout<<cnt-1<<endl;
    }
void dfs(int index){
    if(index==city)return;//当前遍历到的城市编号等于需要删除的城市的编号
    vis[index]=true;
    for(int j=0;j<G[index].size();j++){
        if(vis[G[index][j]]==false){
            dfs(G[index][j]);
        }
    }
    
}
//图的遍历
//给定1个无向图并规定:
	//当删除图中某个顶点的时候,与之链接的边一起删除
//接下来给出k个查询
	//每个查询给出1个欲删除的顶点编号,求删除该顶点(和与其链接的边)后需要增加多少条便,才能让图联通

```cpp
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

int n,m,q;
vector<int>G[1010];
bool vis[1010];
int city;

void dfs(int index){
    if(index==city)return;//当前遍历到的城市编号等于需要删除的城市的编号
    vis[index]=true;
    for(int j=0;j<G[index].size();j++){
        if(vis[G[index][j]]==false){
            dfs(G[index][j]);
        }
    }
    
}

int main()
{
    cin>>n>>m>>q;
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;//--------写到这,手又忍不住要写Union(a,b)了- -,无语
        G[a].push_back(b);//建立关系
        G[b].push_back(a);
    }
    
    for(int i=0;i<q;i++){
        cin>>city;
        memset(vis,false,sizeof(vis));//恢复原状
        int cnt=0;
        //1 2 3//如何求1.多个2.没有某个顶点的图的联通块数?//
        for(int j=1;j<=n;j++){//The cities are numbered from 1 to N.
            if(j!=city&&vis[j]==false){//不是被删除并且没被访问过的城市//遍历不是删除城市的顶点
                dfs(j);//遍历顶点i所在的连通块,depth没用,就没写//写到这,又想写if条件,重新init(),Union(),计算联通块数了
                cnt++;
            }
        }
         cout<<cnt-1<<endl;
    }
    return 0;
}
//我们遍历整个图,就需要对所有的连通块分别进行遍历
//如果给定的图是一个连通图,则只需要一次dfs就能遍历完图---注意啊,是说在main()调用一次dfs,不用for所有顶点来试了
把每个顶点当作根节点来遍历,来寻找连通块(标记访问的节点,下次不访问)

// //沿着一条路径直到无法继续前进
// //才退回到路径上里当前顶点最近的&还存在未访问的岔道口
// //并前往访问那些未访问的分支顶点
// //直到遍历完这个图

//3 2 3–n,m,k------城市数,道路数,需要检查(删除)的城市数---------------这咋又让我想到了红色警报
//随后m行
//1 2-----某条道路2端的2个城市编号
//1 3-----某条道路2端的2个城市编号
//1 2 3--------------k个(3个)需要删除的城市编号–检查

//----------------
//1
//0
//0

//A.需要加几条边,使得整个图联通
	//添加的边数=联通块数-1-----------------------------》让我想到了father[faA]=faB,并查集是合并2棵没有交集的树,有交集不行
//B.求无向图G的连通块数---------------》无向图----》我是你的好朋友,那你也是我的好朋友的感jio
	//a.图的遍历
	//b.并查集

//1.图的遍历dfs
//由于是无向图,因此在读入数据时,要把2个方向的边都进行存储---------------让我想到了 排座位 的二维数组 记录法

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

int n, m, q,city;
vector<int> G[1010];//邻接表
bool vis[10010];

void dfs(int v){
	if (v == city)return;
	vis[v] = true;
	for (int i = 0; i < G[v].size(); i++){//--------和静态树的遍历意昂
		if (vis[G[v][i] == false])
			dfs(G[v][i]);
	}

}

int main() {
	cin >> n >> m >> q;
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		G[a].push_back(b);
		//让我想到了树的 静态写法,只不过那是node[父节点编号].push_back(子节点编号)
		//而这个双向的,树的话只能从上到下遍历---dfs
		G[b].push_back(a);
	}
	for (int i = 0; i < q; i++) {
		//int city;
		cin >> city;
		memset(vis, false, sizeof(vis));//初始化vis数组为false
		int block = 0;//连通块个数,初始化为0
		for (int i = 1; i <= n; i++) {//枚举每个顶点
			if (i != city && vis[i] == false) {
				dfs(i);//遍历顶点i所在的连通块
				block++;//联通块数+1----------
				//他前面遍历一定做了标记-哪些访问过了,后来筛选进入遍历的城市,有条件控制block++
			}
		}
		cout << block - 1<<endl;
	}
	return 0; 
}

//2.并查集



//问题:给一个图,图中有n个顶点,m条边,求图中连通块的个数。

//以下有两种方法可用:1.DFS 2.并查集

//1.用邻接矩阵存图,dfs找连通块数

.#include<bits/stdc++.h> 
const int N=1005;
using namespace std;
vector<int> t[N]; 
int vis[N]={0};
void dfs(int k)
{
    for(int i=0;i<t[k].size();i++)
    {
        if(vis[t[k][i]]==0)
        {   vis[t[k][i]]=1;
            dfs(t[k][i]);
        }
    }
}
int main()
{
    int n,m;//n个顶点,m条边 
    cin>>n>>m;
    int a,b;//边所连接的两个顶点
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        t[a].push_back(b);
        t[b].push_back(a);
    }
    
    int ans=0;//记录连通块数量 
    for(int i=1;i<=n;i++)
    {
        if(vis[i]==0)
        {
            vis[i]=1;
            dfs(i);
            ans++; 
        }      
    }
    cout<<ans<<endl;
    return 0;
}

2.并查集思想,每个顶点找其父节点(find函数),若父节点相同,则属于同一个连通块。

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m;
vector<int> t[N];
int pre[N],root[N];

void init(int nn)
{
    for(int i=1;i<=nn;i++)
    pre[i]=i;
} 
int find(int x)
{
    int f=x;
    while(x!=pre[x])//找到x的父节点 
    x=pre[x];


    int j;
    while(f!=pre[f])//依次将x上面的节点的父节点赋为x; 
    {
        j=f;
        f= pre[f];
        pre[j]=x;
    }
    return x;
}

void merge(int a,int b)
 {
     int t1,t2;
     t1=find(a);
     t2=find(b);
     if(t1!=t2)
     {
         pre[t2]=t1;
     }
}

int block(int nn)
{
    int ans=0;
    for(int i=1;i<=nn;i++)
    root[pre[i]]=1;
    for(int i=1;i<=nn;i++)
    ans+=root[i];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    int a,b;//边所连接的两个顶点
    init(n);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        t[a].push_back(b);
        t[b].push_back(a);
        merge(a,b);
    }
    printf("%d",block(n));
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值