图论知识点 积累 (欧拉回路)(Inspector’s Dilemma)

欧拉道路
在每条边只能走一次的情况下,遍历图中所有的边

欧拉回路
在每条边只能走一次的情况下,遍历图中所有的边然后回到原点

欧拉道路判定
连通块中恰好具有 两个 奇度节点时(起点和终点)为欧拉道路!

欧拉回路判定
连通块中所有节点都是 偶度节点时为欧拉回路(基于dfs进行判定)

例题1
清理道路
给出n个城市

每对城市都有一条双向通道
现在给出m条需要清理的道路

给出m行,每行 给出该道路 所连接的两个城市
我们可以从任意城市出发,要求走完所有的m条道路
问最少次数是多少

这就需要用到 欧拉道路 的知识
如果一个这m条边组成的图正好是一个欧拉道路,不就说明每条边走一次就可以恰好遍历每条边吗,这样走的最少次数就是m次!

考虑图的联通问题
在这个题中,我们的图是构建在一个大图当中的一个子图
所以会存在连通块不只一个的情况

但是本题说,任意两个城市之间都有一条双向的道路
所以只要在两个连通块之间 加 1条边即可!
统计联通块的个数,额外加的边数=连通块的个数-1

图不联通

在这里插入图片描述
建一座额外的桥
在这里插入图片描述

考虑不是欧拉道路的情况
在这里插入图片描述
比如这个图,所有节点的度数都是3,并且有4个,显然不是一个欧拉道路,不可能一次性不重复走完所有的边,但是我们要求最短次数,怎么办?
在这里插入图片描述
我们可以假设在任意两点之间,又创建了一个新边,这样一条边可以让两个
度数为奇数的点 变成 偶数度,所以针对 一个连通块中,奇数度点X时,我们只需要额外建边(假想)最终使其的奇数度点数变成两个(欧拉道路)这样仍然是最短路径,额外建边的数量=(x-2)/2

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
int du[N];
vector<int> ve[N];//这是个技巧的地方,在利用 dfs遍历图时,可以先用vector二维存一下
// 每个节点联通的方向,否则暴力搜索会超时。这样可以直接找到每个城市所联通的城市! 
int vis[N];
int ans,ans1;

int dfs(int x)//利用深搜判断联通块中的  度数 个数! 
{
    int sum=0;///度数为奇数的  节点的个数!! 
    vis[x]=1;
    for(int i=0;i<ve[x].size();i++)
    {
        if(!vis[ve[x][i]])
        sum+=dfs(ve[x][i]);
    }
    if(du[x]%2)
    return sum+1;
    return sum;
}//联通块中奇数 度节点的个数! 

int main()
{
    int n,m,t;
    int num=1;
    while(cin>>n>>m>>t&&(n||m||n))
    {
        for(int i=0;i<=n;i++)
		ve[i].clear();
		
        memset(du,0,sizeof du);
        memset(vis,0,sizeof vis);
        
        for(int i=0;i<m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            du[a]++;
            du[b]++;
            ve[a].push_back(b);
            ve[b].push_back(a);
        }
        
        
        ans=0;//连通块的个数! 
        ans1=0;
        for(int i=1;i<=n;i++)
        {
            if(du[i]&&!vis[i])
			//如果度为0,说明这个点不在这个连通块中!,vis[i]=1,说明节点被访问过! 
			//已经在连通块中被访问过了! 
            {
                ans++; 
                int x=dfs(i);//x为联通块 节点中  奇数度的个数!!! 
                if(x>2)
                ans1+=(x-2)/2;
                
                //这里时本题关键内容! 
                //在连通块里建边,让他变成欧拉回路
				//统计奇度点的个数X,目的是让 个数变成2
				//所以新建的边数 就是 (x-2)/2! 
            } 
        }
        if(ans>0)
        ans--;
        
        
        //ans是联通块的个数 -1; 
        //这里统计连通块的个数
		
		//是由于,我们要在两个连通块之间搭建一条  “桥 ” 让两个连通块相通!!!
		//如果修理的道路中不在一个连通块中,那么就不可避免地要 在连通块之间搭桥! 
		 
        cout<<ans<<" "<<ans1<<" "<<m<<endl;
        printf("Case %d: %d\n",num++,t*(ans+ans1+m));//至少要走m条路
		
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值