1. 程式人生 > >圖論 模板(3)

圖論 模板(3)

一筆畫問題(尤拉路)

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;
}