SGU 101

转载:http://hi.baidu.com/zyz913614263/item/7ef07c5c52200305da163576

今天第一次写欧拉回路的题,虽说之前看过此类算法,但是实践起来还是有区别的。

求欧拉回路的一种解法
  下面是无向图的欧拉回路输出代码:注意输出的前提是已经判断图确实是欧拉回路。
  int num = 0;//标记输出队列
  int match[MAX];//标志节点的度,无向图,不区分入度和出度
  void solve(int x)
  {
       if(match[x] == 0)
              record[num++] = x;
       else
      {
             for(int k =1;k<=n;k++)
             {
                       if(vis[x][k] !=0 )
                    {
                                  vis[x][k]--;
                                  vis[k][x]--;
                                  match[x]--;
                                  match[k]--;
                                  solve(k);
                     }
              }
             record[num++] = x;
      }
    }
  注意record中的点的排列是输出的到序,因此,如果要输出欧拉路径,需要将record倒过来输出。(跟DFS一样,不解释了)
  求欧拉回路的思路:
  循环的找到出发点。从某个节点开始,然后查出一个从这个出发回到这个点的环路径。这种方法保证每个边都被遍历。如果有某个点的边没有被遍历就让这个点为起点,这条边为起始边,把它和当前的环衔接上。这样直至所有的边都被遍历。这样,整个图就被连接到一起了。<其实就是DFS遍历图,没什么区别>
  具体步骤:
  1。如果此时与该点无相连的点,那么就加入路径中;
  2。如果该点有相连的点,那就列一张表,遍历这些点,知道没有相连的点。
  3。处理当前的点,删除走过的这条边,并在其相邻的点上进行同样的操作,并把删除的点加入到路径中去。
  4。这个其实是个递归过程。<DFS求解>


对于这题一条边的两个端点,作为两个点(0~6)见一个最多六个点的图,然后打印欧拉回路

最后,判断是输入中的哪条边就可以了。


#include <cstdio>
#include <cstring>

using namespace std;

const int maxn = 12;
const int maxm = 120;


int vis[maxn][maxn],used[maxn];
int match[maxn],f[maxn],num,n;
//int num = 0;//标记输出队列
//int match[MAX];//标志节点的度,无向图,不区分入度和出度


struct node{
    int x,y;
}p[maxm];


int record[maxm];
int cnt[maxm];


void dfs(int v)
{
	for(int i=0;i<=6;i++)  // 0~6 
    	if(vis[v][i]&&!used[i])
        {
        	used[i]=1;
        	dfs(i);
        }
}


void solve(int x)
{
	if(match[x]==0) record[num++]=x;
	else
	{
		for(int k=0;k<=6;k++)  // 0 ~ 6
		{
			if(vis[x][k]!=0)
			//if(vis[x][k]>0)
			{
				vis[x][k]--;
				vis[k][x]--;
				match[x]--;
				match[k]--;
				solve(k);
			}
		}
		record[num++]=x;
	}
}


int main()
{
	scanf("%d",&n);
	memset(match,0,sizeof(match));
	memset(vis,0,sizeof(vis));
	memset(f,0,sizeof(f));	
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&p[i].x,&p[i].y);
		match[p[i].x]++;
		match[p[i].y]++;
		vis[p[i].x][p[i].y]++;
		vis[p[i].y][p[i].x]++;
		f[p[i].x]=1;
		f[p[i].y]=1;
	}
	used[p[0].x]=1;
	dfs(p[0].x);
	for(int i=0;i<=6;i++)
   		if(!used[i]&&f[i])
   		{
    		printf("No solution\n");
    		return 0;
   		}
	int s=0,flag=-1;
	for(int i=0;i<=6;i++)
   		if(match[i]%2&&f[i])
   		{
    		s++;
    		flag=i;
   		}
	if(s==1||s>=3)
	{
		printf("No solution\n");
   		return 0;
	}
	num=0;
	if(s==2)
	{
		solve(flag);
	}
	else  solve(p[0].x);
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<num-1;i++)
	{
		for(int j=0;j<n;j++)
   		if(p[j].x==record[i]&&p[j].y==record[i+1]&&!cnt[j])
   		{
    		cnt[j]=1;
    		printf("%d +\n",j+1);
    		break;
   		}
   		else if(p[j].y==record[i]&&p[j].x==record[i+1]&&!cnt[j])
   		{
    		cnt[j]=1;
    		printf("%d -\n",j+1);
    		break;
   		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值