图论 - 欧拉路径与欧拉回路

申必的SI120刚好讲到这里,于是回去复习了一下板子。

*知识点部分待补

2.习题

P2731 [USACO3.3] 骑马修栅栏 Riding the Fences

求字典序最小的无向图欧拉路径,图中有孤立点,但保证去掉孤立点的图联通。

const int N=1E3+5;
int n, m;
vector<int> G[N];
int deg[N], mp[N][N], nxt[N];
//nxt下一个遍历到的边
int st[N*8], t;

void dfs_Euler(int x) //Hierholzer 算法
{
    for(int i=nxt[x]; i<(int)G[x].size(); i=nxt[x])
    {
        nxt[x]=i+1;
        //边能走则走这条边往下探
        if(mp[x][G[x][i]])
        {
        	--mp[x][G[x][i]], --mp[G[x][i]][x];//删边 
        	dfs_Euler(G[x][i]);
		}
    }
    //何时回溯?所有边都走不了了 
    st[++t]=x;
    //回溯的过程就是将回路不断加入路径的过程 
}

inline int Solve()
{
    #ifdef DEBUG
    printf("Debuging...\n");
    #endif

    n=500, m=read();
    for(int i=1; i<=m; i++)
    {
        int u=read(), v=read();
        G[u].push_back(v), ++deg[u];
        G[v].push_back(u), ++deg[v];
        ++mp[u][v], ++mp[v][u];
    }
    //判定+确定起终点 
    bool flag=true;
    int in=-1, out=-1, min_v=-1;
    for(int i=1;flag && i<=n;i++)
    {
    	if(min_v==-1 && deg[i]) min_v=i;
    	if(deg[i]&1)
    	{
    		if(in==-1) 		 in=i;
    		else if(out==-1) out=i;
    		else 			 flag=false;
		}
	}
	if(in==-1 && out==-1) in=out=min_v;
	if(!flag) return printf("No\n");
    //获得字典序最小的路径 
    for(int i=1; i<=n; i++) sort(G[i].begin(), G[i].end());
    dfs_Euler(in);
    for(int i=t; i; i--) printf("%d\n", st[i]); putchar('\n');

    return 0;
}

P7771 【模板】欧拉路径

求字典序最小的有向图欧拉路径,保证图弱联通。

int n, m;
vector<int> G[N];
int ideg[N], odeg[N], nxt[N]; //mp[N][N]
//nxt下一个遍历到的边
int st[N*8], t;

void dfs_Euler(int x) //Hierholzer 算法
{
    for(int i=nxt[x]; i<(int)G[x].size(); i=nxt[x])
    {
        nxt[x]=i+1;
        //边能走则走这条边往下探
		//删边: 往后面的边找就是删掉前面的边了
		//      有向图也不用根据方向查重 
        dfs_Euler(G[x][i]);
    }
    //何时回溯?所有边都走不了了 
    st[++t]=x;
    //回溯的过程就是将回路不断加入路径的过程 
}

inline int Solve()
{
    #ifdef DEBUG
    printf("Debuging...\n");
    #endif

    n=read(), m=read();
    for(int i=1; i<=m; i++)
    {
        int u=read(), v=read();
        G[u].push_back(v);
		++ideg[v], ++odeg[u];
    }
    //判定+确定起终点 
    bool flag=true;
    int in=-1, out=-1, min_v=-1;
    for(int i=1;flag && i<=n;i++)
    {
    	if(odeg[i]==ideg[i])
    	{
    		if(min_v==-1 && ideg[i]) min_v=i;
		}
		else if(odeg[i]==ideg[i]+1)
		{
			if(in==-1) in=i;
			else flag=false;
		}
		else if(odeg[i]+1==ideg[i])
		{
			if(out==-1) out=i;
			else flag=false;
		}
		else
			flag=false; 
	}
	if(in==-1 && out==-1) in=out=min_v;
	//else if(in==-1 || out==-1) flag=false;
	if(!flag) return printf("No\n");
    //获得字典序最小的路径 
    for(int i=1; i<=n; i++) sort(G[i].begin(), G[i].end());
    dfs_Euler(in);
    for(int i=t; i; i--) printf("%d ", st[i]); putchar('\n');

    return 0;
}
posted @ 2024-06-06 21:25  Coinred  阅读(4)  评论(0编辑  收藏  举报