图论 模板(3)

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/84501069

一笔画问题(欧拉路)

DFS版

/*1.一笔画问题
*规定	所有的边都只能画一次,不能重复画
*输入
	第一行只有一个正整数N(N<=10)表示测试数据的组数.
	每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),
	分别表示这个画中有多少个顶点和多少条连线.
	(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0 < A,B < P),
	表示编号为A和B的两点之间有连线.
*输出
	如果存在符合条件的连线,则输出"Yes",
	如果不存在符合条件的连线,输出"No".
*样例输入
	2
	4 3
	1 2
	1 3
	1 4
		4 5
		1 2
		2 3
		1 3
		1 4
		3 4
*样例输出
	No
		Yes
*/
//DFS version: 
#include<bits/stdc++.h>
#define _ 1002
using namespace std;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
	return num*f;
}
vector<int> graph[_];
int n,m,cnt,odd;
bool v[_];

void dfs(int x)
{
    for(int i=0,y;i<graph[x].size();i++)
    	if(!v[y=graph[x][i]])
        {
            cnt++;
            if(graph[y].size()%2) odd++;                
            v[y]=true;
            dfs(y);
        }
}

int main()
{
    int t=read();
    while (t--)
	{
        n=read(),m=read();
        for(int i=0;i<=n;i++)
            graph[i].clear();
		for(int i=0;i<m;i++)
        {
            int x=read(),y=read();
            graph[x].push_back(y);
            graph[y].push_back(x);
        }
		cnt=0,odd=0;
        memset(v,false,sizeof(v));
        dfs(1);
		if((m==0&&n==1)||(cnt==n&&(odd==0||odd==2))) printf("Yes\n");
        else printf("No\n");       
    }
    return 0;
}

并查集版

/*1.一笔画问题
*规定	所有的边都只能画一次,不能重复画
*输入
	第一行只有一个正整数N(N<=10)表示测试数据的组数.
	每组测试数据的第一行有两个正整数P,Q(P<=1000,Q<=2000),
	分别表示这个画中有多少个顶点和多少条连线.
	(点的编号从1到P) 随后的Q行,每行有两个正整数A,B(0 < A,B < P),
	表示编号为A和B的两点之间有连线.
*输出
	如果存在符合条件的连线,则输出"Yes",
	如果不存在符合条件的连线,输出"No".
*样例输入
	2
	4 3
	1 2
	1 3
	1 4
		4 5
		1 2
		2 3
		1 3
		1 4
		3 4
*样例输出
	No
		Yes
*/
//并查集方法
#include<bits/stdc++.h>
#define _ 1005
using namespace std;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0',ch=getchar();
	return num*f;
}
int degree[_];//度 
int fa[_];
int get(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=get(fa[x]);
}
int main()
{
    int t=read();
    while(t--)
    {
        memset(degree,0,sizeof(degree));
        for(int i=0;i<_;++i)
        	fa[i]=i;
        int n=read(),m=read();
        for(int i=1;i<=m;++i)
        {
            int x=read(),y=read();
            degree[x]++;
            degree[y]++;
            int rx=get(x);
    		int ry=get(y);
    		fa[ry]=rx;
        }

        int root=get(1),cnt=0,odd=0;
        for(int i=1;i<=n;++i)
        {
            if(get(i)!=root)
                cnt++;
            if(degree[i]%2)//度为奇数
                odd++;//odd 奇数
        }
		if(!cnt&&(odd==0||odd==2)) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

欧拉路

https://www.luogu.org/problemnew/show/P2731

#include<bits/stdc++.h>
#define _ 1025
using namespace std;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') num=(num<<1)+(num<<3)+ch-'0', ch=getchar();
	return num*f;
}
int G[_][_],degree[_];
int n,m;
stack<int>s;//用一个栈来保存路径 
void dfs(int x)
{
	for (int i=1;i<=n;++i)
		if (G[x][i])
		{
			G[x][i]--;
			G[i][x]--;//防止重复走同一边 
			dfs(i);
		}
	s.push(x);
}
int main()
{
	m=read();
	for (int i=1;i<=m;++i)
	{
		int x=read(),y=read();
		n=max(n,x),n=max(n,y);
		G[x][y]++,G[y][x]++;
		degree[x]++,degree[y]++;
	}//用邻接矩阵存图 
	int u=1;
	for (int i=1;i<=n;++i)
		if (degree[i]%2)
		{
			u=i;//起点 
			break;
		}
	dfs(u);
	while (!s.empty())
	{
		printf("%d\n",s.top());//倒序输出 
		s.pop();
	}
	return 0;
}

构建邻接表

/*
*构建邻接表模板
*/
#include<stdio.h>
#include<string.h>
int head[100100];//表头,head[i]代表起点是i的边的编号
int cnt;//代表边的编号
struct s
{
    int u;//记录边的起点
    int v;//记录边的终点
    int w;//记录边的权值
    int next;//指向上一条边的编号
}edge[100010];
void add(int u,int v,int w)//向所要连接的表中加入边
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int i;
        cnt=0;
        memset(head,-1,sizeof(head));//清空表头数组
        for(i=0;i<n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
        }
        int u,v,w;
        scanf("%d",&u);
        for(i=head[u];i!=-1;i=edge[i].next)//输出所有与起点为u相连的边的终点和权值
        {
            v=edge[i].v;
            w=edge[i].w;
            printf("%d %d\n",v,w);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/84501069
今日推荐