返回顶部

欧拉路径

借鉴文章
\(1\). 欧拉路径定义
图中经过所有边恰好一次的路径叫欧拉路径(也就是一笔画)。如果此路径的起点终点相同,则称其为一条欧拉回路
\(2.\) 欧拉路径判定(是否存在)

  • 有向图欧拉路径:图中恰好存在 \(1\) 个点出度比入度多 \(1\)(这个点即为 起点 \(S\)),\(1\) 个点入度比出度多 \(1\)(这个点即为 终点 \(T\)),其余节点出度=入度。

  • 有向图欧拉回路所有点的入度=出度(起点 \(S\) 和终点 \(T\) 可以为任意点)。

  • 无向图欧拉路径:图中恰好存在 \(2\) 个点的度数是奇数,其余节点的度数为偶数,这两个度数为奇数的点即为欧拉路径的 起点 \(S\)终点 \(T\)

  • 无向图欧拉回路所有点的度数都是偶数(起点 \(S\) 和终点 \(T\) 可以为任意点)。

注:存在欧拉回路(即满足存在欧拉回路的条件),也一定存在欧拉路径。

当然,一副图有欧拉路径,还必须满足将它的有向边视为无向边后它是连通的(不考虑度为 \(0\) 的孤立点),连通性的判断我们可以使用并查集dfs 等。

例题

欧拉路径

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1e5+5;
std::vector<int> edge[N];
int n,m;
int in[N],out[N],cnt[2],del[N];
stack <int> sta;bool vis[N];
int main()
{
	speed();
   // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
	cin>>n>>m;
	int u,v;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v;
		edge[u].push_back(v);
		out[u]++;in[v]++;
	}
	for(int i=1;i<=n;i++) sort(edge[i].begin(),edge[i].end());
	bool equal=1;int st=1;//注意默认起点
	for(int i=1;i<=n;i++)
	{
		if(out[i]!=in[i])
		{
			equal=0;
			if(out[i]-in[i]==1)cnt[1]++,st=i;
			else if(in[i]-out[i]==1)cnt[0]++;
			else return cout<<"No"<<endl,0;
		}
	}
	if((!equal)&&!(cnt[0]==cnt[1]&&cnt[0]==1)) return cout<<"No"<<endl,0;
	auto dfs=[&](auto dfs,int u) ->void{
		for(int i=del[u];i<edge[u].size();i=del[u])
		{
			del[u]=i+1;int to=edge[u][i];
			dfs(dfs,to);
		}
		sta.push(u);
	};
	dfs(dfs,st);
	while(sta.size())cout<<sta.top()<<" ",sta.pop();
	return 0;
}

骑马修栅栏

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1e4+5;
std::vector<int> edge[N];
int n,m;
int du[N],mp[N][N],st;
stack <int> sta;bool vis[N];
int mi=1e9;
int main()
{
	speed();
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
	cin>>m;
	int u,v;
	for(int i=1;i<=m;i++)
	{
		cin>>u>>v;
		mp[u][v]++;mp[v][u]++;
		du[u]++;du[v]++;
		n=max(n,u);n=max(n,v);
		mi=min(u,mi);mi=min(mi,v);
	}
	st=mi;//注意默认起点
	for(int i=1;i<=n;i++)
	{
		du[i]%2?({st=i;break;}):({continue;});
	}
	auto dfs=[&](auto dfs,int u) ->void{
		for(int i=1;i<=n;i++)
		{
			if(mp[u][i])
			{
				mp[u][i]--;
				mp[i][u]--;
				dfs(dfs,i);
			}
		}
		sta.push(u);
	};
	dfs(dfs,st);
	while(sta.size())cout<<sta.top()<<endl,sta.pop();
	return 0;
}

P1341 无序字母对

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 250+5;
int n;
stack <char> sta;
char mp[N][N];
char du[N];
int main()
{
	speed();
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
	cin>>n;
	char op[3];
	char st=0;
	for(int i=1;i<=n;i++)
	{
		cin>>op;
		mp[op[0]][op[1]]=1;
		mp[op[1]][op[0]]=1;
		du[op[1]]++;du[op[0]]++;
	}
	// cout<<st<<endl;
	int cnt=0;
	for(char i='A';i<='z';i++)
	{
		if(i>'Z'&&i<'a')i='a';
		if(du[i]%2)
		{
			cnt++;
			if(!st)st=i;
			// break;
		}
	}
	if(!st)
	{
		for(char i='A';i<='z';i++)
		{
			if(i>'Z'&&i<'a')i='a';
			// cout<<i<<endl;
			if(du[i])
			{
				st=i;break;
			}
		}
	}
	auto dfs=[&](auto dfs,char u) ->void{
		// cout<<u<<endl;
		for(char i='A';i<='z';i++)
		{
			if(i>'Z'&&i<'a')i='a';
			if(mp[u][i]>0)
			{
				// cout<<mp[u][i]<<endl;
				mp[u][i]--;
				mp[i][u]--;
				dfs(dfs,i);
			}
		}
		// cout<<u<<endl;
		sta.push(u);
	};
	dfs(dfs,st);
	if((cnt&&cnt!=2)||sta.size()<n+1)
	{
		cout<<"No Solution"<<endl;
		return 0;
	}
	while(sta.size())cout<<char(sta.top()),sta.pop();
	return 0;
}

P1127 词链

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 2000+5;
int n;
string s[N];bool used[N];
int in[N],out[N];
vector <int> edge[N];
void dfs(int S, std::string curr, int count) {
	if (count == n) {
		curr[curr.length() - 1] = ' ';
		std::cout << curr;
		exit(0);
	}
	for (auto i : edge[S])
		if (!used[i]) {
			used[i] = true;
			dfs(i, curr + s[i] + '.', count + 1);
			used[i] = false;
		}
}
int main()
{
	speed();
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		int len=s[i].size()-1;
		in[s[i][0]]++;out[s[i][len]]++;
	}
	std::sort(s + 1, s + n + 1);
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			if (i != j && s[i][s[i].length() - 1] == s[j][0])
				edge[i].push_back(j);
	for (int i = 1; i <= n; ++i)
		if (in[s[i][0]] == out[s[i][0]] + 1) {
			used[i] = true;
			dfs(i, s[i] + '.', 1);
			used[i] = false;
		}
	used[1] = true;
	dfs(1, s[1] + '.', 1);
	used[1] = false;
	std::cout << "***";
	return 0;
}

image

思路:我们可以类似\(hash\)把前\(m-1\)位表示为\(n\)进制下的数,第m位看成m个边,这样所有状态都能表示出来,跑欧拉回路,具体连边为后\(\sum_{x=0}^{n-1}436653->36653x\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1E6+5; 
int n,m,cnt,f[N],del[N],vis[N];
vector <pii> edge[N];
stack <int> sta;
void calc(int len,int sum)
{
    if(len==m-1)
    {
        f[++cnt]=sum;
        return;
    }
    for(int i=0;i<=n-1;i++)
    {
        calc(len+1,sum*n+i);
    }
}

int main()
{
    // freopen("in.in","r",stdin);
    // freopen("out.out","w",stdout);
    cin>>n>>m;
    if(n==1)
    {
        cout<<m<<endl;
        for(int i=1;i<=m;i++)
        {
            cout<<0<<" ";
        }
    }
    else if(m==1) 
    {
        cout<<n<<endl;
        for(int i=0;i<=n-1;i++)cout<<i<<" ";
    }else
    {
        calc(0,0);
        ll p=pow(n,m-2);int tot=0;
        for(int i=1;i<=cnt;i++)
        {   
            for(int j=0;j<=n-1;j++)
            {
                tot++;
                edge[i].pb({lower_bound(f+1,f+1+cnt,(f[i]%p)*n+j)-f,tot});
				//含义为一个n进制数   12345*
															  *23451这种方式相连																//
                // cout<<f[i]<<" "<<lower_bound(f+1,f+1+cnt,(f[i]%p)*n+j)-f<<endl;
            }
        }
        auto dfs=[&](auto dfs,int x)->void{
            for(int i=del[x];i<(int)edge[x].size();i=max(del[x],i+1))
            {
                if(vis[edge[x][i].second]==0)
                {
                    vis[edge[x][i].second]=1;
                    del[x]=i+1;
                    dfs(dfs,edge[x][i].first);
                }
            }
            sta.push(x);
        };
        dfs(dfs,1);
        cout<<sta.size()-1<<endl;
        while(sta.empty()==0)
        {
            int x=sta.top();
            sta.pop();
            if(sta.empty()==0)
            {
                cout<<f[sta.top()]-(f[x]%p)*n<<" ";
            }
        }
    }       

    return 0;
}

posted @ 2024-08-13 19:58  wlesq  阅读(133)  评论(0编辑  收藏  举报