洛谷 P2731 [USACO3.3]骑马修栅栏 Riding the Fences
题意描述
每个栅栏是一条无向边,找出字典序最小的欧拉路。数据保证至少有一个解。
最多 \(500\) 个点, \(1024\) 条边。
分析
看着如此微小的数据范围,随便瞎搞都行使用矩阵来存储边,同时记录每个点的度。
根据欧拉路的要求,如果图中存在唯一/唯二的奇度点,那么起点一定是这个点/这两个点中更小的点。如果都是偶度点,则根据字典序最小的原则,从最小序号的点出发。
值得注意的是,可能有重边,所以每次dfs进入一个点时,不应该把这条边清零,而是减少一条边即可。
至于输出答案,不能在刚刚进入dfs的时候就输出,否则就会贪心贪错了。试想,从一个奇度点出发,这搜索路上可能会先遇到另一个奇度点,结果就先进入了这个点,把这个奇度点直接输出了!那当然是不行的!那么应该如何做呢?只需在回溯的时候用栈记录这个点即可,这样先回溯的这个点(第一个回溯的一定是第二个奇度点)会先被压入栈底,最后倒叙输出即可。
示范:
void dfs(int x)
{
//	cout<<x<<endl; //wrong answer
	for(re int i=minn;i<=maxn&&!succ;i++)
	{
		if(map[x][i])
		{
			
			map[x][i]--;map[i][x]--;
			dfs(i);
		}
	}
	way.push_back(x); //accept
}
Code
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<queue>
#include<vector>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#define re register
#define debug printf("Now is %d\n",__LINE__);
using namespace std;
template<class T>inline void read(T&x)
{
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
}
inline int read()
{
	int x=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    x=ch-'0';ch=getchar();
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x;
}
int G[55];
template<class T>inline void write(T x)
{
    int g=0;
    if(x<0) x=-x,putchar('-');
    do{G[++g]=x%10;x/=10;}while(x);
    for(re int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
int map[600][600];
int m,maxn=0,minn=1000;
int degree[600];
vector<int>way;
bool succ;
void dfs(int x)
{
//	cout<<x<<endl; 
	for(re int i=minn;i<=maxn&&!succ;i++)
	{
		if(map[x][i])
		{
			
			map[x][i]--;map[i][x]--;
			dfs(i);
		}
	}
	way.push_back(x);
}
int main()
{
	m=read();
	for(re int i=1,a,b;i<=m;i++)
	{
		a=read();
		b=read();
		map[a][b]++;map[b][a]++;
		degree[a]++;
		degree[b]++;
		maxn=max(maxn,max(a,b));
		minn=min(minn,min(a,b));
	}
	re int flag=0;	
	for(re int i=minn;i<=maxn;i++) if(degree[i]) {flag=i;break;}
	for(re int i=minn;i<=maxn;i++) if(degree[i]&1) {flag=i;break;}
	dfs(flag);
	while(!way.empty()) cout<<way.back()<<endl,way.pop_back();
	return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号