欧拉道路与欧拉回路

欧拉道路是指不重复的经过图的每一条边所形成的道路

欧拉回路是指不重复的经过图的每一条边所形成的回路

这类问题都可以使用dfs来求解

下面给出几道例题

1.P6066 [USACO05JAN] Watchcow S

解析:

一道模板题,建好双向边,走过一次删掉一条

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
int n,m,vis[N];
struct node{
    int to,visit;
};
stack<int>st;
vector<node>G[N];
void dfs(int x){
    for(int i=vis[x];i<G[x].size();i=vis[x]){
        vis[x]=i+1;
        if(G[x][i].visit)continue;
        G[x][i].visit=1;
        dfs(G[x][i].to);
    }
    st.push(x);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int x,y;cin>>x>>y;
        G[x].push_back({y,0});
        G[y].push_back({x,0});
    }
    dfs(1);
    while(st.size()){
        cout<<st.top()<<'\n';
        st.pop();
    }
    return 0;
}

  

2.P7771 【模板】欧拉路径

解析:

模板题,判断有向图是否存在欧拉路径,只需要看度,如果存在入度和出度不等的,判断一下,分三种情况:1.入度-出度=1,cnt++ 2.出度-入度=1,cnt1++,并将起点设为当前点的编号  3.直接输出No

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
vector<int>G[N];
stack<int>st;pair<int,int>cnt={0,0};
int n,m,vis[N],din[N],dout[N],is=1,s=1;
void dfs(int x){
    for(int i=vis[x];i<G[x].size();i=vis[x]){
        vis[x]=i+1;
        dfs(G[x][i]);
    }
    st.push(x);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int x,y;cin>>x>>y;
        G[x].push_back(y);
        din[y]++;dout[x]++;
    }
    for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end());
    for(int i=1;i<=n;i++){
        if(din[i]!=dout[i]){
            is=0;
            if(din[i]-dout[i]==1)cnt.first++;
            else if(dout[i]-din[i]==1){
                cnt.second++;
                s=i;
            }else{
                cout<<"No";
                return 0;
            }
        }
    }
    if((!is)&&!(cnt.first==cnt.second&&cnt.first==1)){
        cout<<"No";
        return 0;
    }
    dfs(s);
    while(st.size()){
        cout<<st.top()<<' ';
        st.pop();
    }
    return 0;
}

  

3.P1341 无序字母对

解析:
使用字母编号跑欧拉路径的模版即可,编号规则:A~Z为1~26,a~z为27~52

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+39+7;
int calc(char c){
    if(c<='z'&&c>='a')return c-'a'+27;
    else return c-'A'+1;
}
char uncalc(int n){
    if(n>=27&&n<=52)return n+'a'-27;
    else return n+'A'-1;
}
int n,m,vis[N],d[N],a[N][N];
stack<int>st;
void dfs(int x){
    for(int i=1;i<55;i++){
        if(!a[x][i])continue;
        a[x][i]=a[i][x]=0;
        dfs(i);
    }
    st.push(x);
}
int main(){
    cin>>n;
    int k=0x3f3f3f3f;
    for(int i=1;i<=n;i++){
        string s;cin>>s;
        a[calc(s[0])][calc(s[1])]=a[calc(s[1])][calc(s[0])]=1;
        ++d[calc(s[0])];++d[calc(s[1])];
        k=min(k,min(calc(s[0]),calc(s[1])));
    }
    int cnt=0,t=0x3f3f3f3f;
    for(int i=1;i<=55&&cnt<=2;i++){
        if(d[i]%2){
            cnt++;
            t=min(t,i);
        }
    }
    if(cnt==1||cnt>2){
        cout<<"No Solution";
        return 0;
    }
    if(cnt==0)dfs(k);
    else dfs(t);
    while(st.size()){
        cout<<uncalc(st.top());
        st.pop();
    }
    return 0;
}

 

4.求子树的权值之和

解析:

使用前缀和,欧拉序等维护权值和,最后前缀和求和即可

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
vector<int>G[N];
int e[N],pos[N][2],len,a[N],sub[N];
void dfs(int x,int fa){
    e[++len]=x;
    pos[x][0]=len;
    int SIZE=G[x].size();
    for(int i=0;i<SIZE;i++){
        if(G[x][i]==fa)continue;
        dfs(G[x][i],x);
    }
    e[++len]=x;
    pos[x][1]=len;
}
int main(){
    int n,m,t;cin>>n>>m>>t;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
        int a,b;cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    dfs(1,0);
    sub[1]=a[e[1]];
    for(int i=2;i<=len;i++)sub[i]=a[e[i]]-a[e[i-1]];
    for(int i=1;i<=m;i++){
        int x,w;cin>>x>>w;
        sub[pos[x][0]]+=w;
        sub[pos[x][1]+1]-=w;
    }
    for(int i=1;i<=len;i++)sub[i]+=sub[i-1];
    for(int i=1;i<=len;i++)sub[i]+=sub[i-1];
    while(t--){
        int x;cin>>x;
        cout<<(sub[pos[x][1]]-sub[pos[x][0]-1])/2<<'\n';
    }
    return 0;
}

  

哈密顿路径与欧拉路径相似,它是一个遍历所有顶点的路径,还有哈密顿回路,顾名思义,就是一条遍历所有顶点的回路

下面给出一道例题

最短哈密顿回路

解析:
使用状压DP,记录所有可能性,进行DP求解最小值的过程

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1<<21,M = 25;
int n,G[M][M],dp[N][M];
int main(){
    memset(dp,0x3f,sizeof(dp));
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>G[i][j];
        }
    }
    dp[1][0]=0;
    for(int i=1;i<(1<<n);i++){
        for(int j=0;j<n;j++){
            if((i>>j)&1){
                for(int k=0;k<n;k++){
                    if((i>>k)&1){
                        int l=i^(1<<j);
                        dp[i][j]=min(dp[i][j],dp[l][k]+G[j][k]);
                    }
                }
            }
        }
    }
    cout<<dp[(1<<n)-1][n-1];
    return 0;
}

  

 

顺便再提一下dfs序

dfs序就是dfs遍历所形成的的序列,这里面需要引入一个新知识点,即时间戳,用来计算第一次和最后一次遍历当前点的时间,非常有用,可以判断y是否为x子节点

下面放上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+39+7;
int n,m,s[N],dfn[N],tim=0,e[N],pos[N],len=0;
vector<vector<int> >G[N];
void dfs(int x,int fa){
    int u=len+1;
    s[++len]=++tim;dfn[len]=x;
    pos[x]=len;
    int SIZE=G[x].size();
    for(int i=0;i<SIZE;i++){
        if(G[x][i]==fa)continue;
        dfs(G[x][i],x);
    }
    e[u]=tim;
}
int main(){
    cin>>n>>m;
    for(int i=1,a,b;i<=m;i++){
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    dfs(1,0);
    for(int i=1,a,b;i<=n;i++){
        cin>>a>>b;
        a=pos[a];b=pos[b];
        if(s[a]<=s[b]&&e[b]<=e[a])cout<<"Yes\n";
        else cout<<"No\n";
    }
    return 0;
}

  

posted @   天雷小兔  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示