圖論 模板(3)
阿新 • • 發佈:2018-11-27
一筆畫問題(尤拉路)
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;
}