201512-4 CSP 真题 送货

201512-4 CSP 真题 送货

在这里插入图片描述在这里插入图片描述

题目分析

学过离散数学应该对欧拉通路不陌生,这道题简单来说就是找一条欧娜通路出来,就是一笔画的问题,且要求从标号1开始,这种题只能用bfs。

dfs(深度优先搜索)

#include<iostream>
#include<algorithm>

using namespace std ;

const int N = 10010 , M = N * 2;
int h[N] , e[M], ne[M], idx ; // h是n个领接表的头,e存的每一个节点的值,ne存的是next指针
int ans = N ;
bool stu[N] ;
int n;
void add(int a , int b)
{
    e[idx] = b ;
    ne[idx] = h[a] ;
    h[a] = idx++ ;
}
void dfs(int num)
{
	stup[num] = true ;
	for(int i = h[u] ; i != -1 ; i = ne[i])
	{
		int j = e[i] ; // 当前点
		if (!stu[j])
		{
			dfs(i) ;
		}
	}
}
int main()
{
    memset(h,-1,sizeof(h)) ;
    // add操作
    // dfs(1)
    return 0 ;
}

上述代码是dfs的经典模板,可以去y总哪里学习一下,awing这个平台。

欧拉通路

如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉通路。
如果一个回路是欧拉通路,则称为欧拉回路。

欧拉回路的判断:
无向图存在欧拉回路的充要条件:
一个无向图存在欧拉回路,当且仅当该图所有顶点度数都为偶数,且该图是连通图。
有向图存在欧拉回路的充要条件:
一个有向图存在欧拉回路,所有顶点的入度=出度且该图是连通图。

欧拉通路的判断(重点!!!!下面要用到)
无向图:
图连通;图中只有0个(即全是偶数节点)或有2个度为奇数的节点。
度为2的时候,这两个点分别为起点和终点

有向图:
图连通;除2个端点外其余节点入度=出度;1个端点入度比出度大1;一个端点入度比出度小1 或 所有节点入度=出度

此题,我们采取领接表存储,用stl中的vectoe Graph[],因为是无向图,注意加边的时候两边都要加上。

图的领接表存储
    for (int i = 1 ; i <= m;++i){
        int start , end ;
        cin >> start >> end ;
        Graph[start].push_back(end) ;
        Graph[end].push_back(start) ;
    }

判断有多少奇度点

将图存储好了之后,我们就要判断一个图有没有欧拉通路存在,注意,有欧拉回路一定有欧拉通路,所以当奇度点等于0和2的时候,我们认为它有欧拉通路,并且题目要求从1开始走,也就是从1开始遍历边,还要满足最小的点走,我们可以在遍历边的时候,将每个领接表中的点进行排序。例如Graph[1]中存的[4,1,5,6],排序完就是[1,4,5,6],那么从1开始遍历的时候,第一条边是1-4,如果将每个点都进行排序,就能保证我们每次走的边到的点都是最小的。判断是否为奇度点也很简单,用size对2模运算就行。

for (int i = 1 ; i <= n ; ++i){
        sort(Graph[i].begin(),Graph[i].end()) ;
        if (Graph[i].size() % 2 == 1){
            k++;
            if (k==1){
                start = i ;
            }
        }
    }

最终代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
// 这种类型的题多思考visited数组和ans类型放在递归的哪个位置
int n , m ;
vector<int> Graph[10001] ;
vector<int> ans ;
bool visited[10005][10005];
void dfs(int num){
    int end ;
    for (int i = 0 ; i < Graph[num].size() ; ++i){
        end = Graph[num][i] ;
        if (visited[num][end]==false){
            visited[num][end]=visited[end][num] = true ;
            dfs(end);
        }
    }
    ans.push_back(num);
}
int main()
{
    cin >> n >> m ;
    for (int i = 1 ; i <= m;++i){
        int start , end ;
        cin >> start >> end ;
        Graph[start].push_back(end) ;
        Graph[end].push_back(start) ;
    }
    int k = 0 ;
    int start = 1;
    for (int i = 1 ; i <= n ; ++i){
        sort(Graph[i].begin(),Graph[i].end()) ;
        if (Graph[i].size() % 2 == 1){
            k++;
            if (k==1){
                start = i ;
            }
        }
    }
    if (k==0||k==2){
        dfs(start);
    }
    if (ans.size()==m+1){
        // for (vector<int>::iterator it = ans.begin();it != ans.end() ; it++){
        //     cout << *it << " " ;
        // }
        for (vector<int>::iterator it = ans.end() - 1;it != ans.begin()-1 ; it--){
            cout << *it << " " ;
        }
    }else{
        cout << -1 ;
    }
    return 0 ;
}

总结

前几年的题目难度还比较简单,但是我还是没做出来,一开始的思想是用领结矩阵遍历点。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值