欧拉道路与欧拉回路
欧拉道路是指不重复的经过图的每一条边所形成的道路
欧拉回路是指不重复的经过图的每一条边所形成的回路
这类问题都可以使用dfs来求解
下面给出几道例题
1.P6066 [USACO05JAN] Watchcow S
解析:
一道模板题,建好双向边,走过一次删掉一条
代码:
#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;
}
解析:
模板题,判断有向图是否存在欧拉路径,只需要看度,如果存在入度和出度不等的,判断一下,分三种情况:1.入度-出度=1,cnt++ 2.出度-入度=1,cnt1++,并将起点设为当前点的编号 3.直接输出No
代码:
#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;
}
解析:
使用字母编号跑欧拉路径的模版即可,编号规则:A~Z为1~26,a~z为27~52
代码:
#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.求子树的权值之和
解析:
使用前缀和,欧拉序等维护权值和,最后前缀和求和即可
代码:
#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求解最小值的过程
代码:
#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子节点
下面放上代码:
#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;
}

浙公网安备 33010602011771号