Play on Words(UVA 10129)(欧拉回路)

题目
一、无向图
每个顶点的度数都是偶数,则存在欧拉回路。

二、有向图(所有边都是单向的)
每个节顶点的入度都等于出度,则存在欧拉回路。

三.混合图欧拉回路
  混合图欧拉回路用的是网络流。
  把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路。

什么时候可以不重复的走完所有边?
(1)对于无向图来说,就是所有点的度为偶数(欧拉回路),或者有且只有两个点的度为奇数其他点为均为偶数(且一定是从一个奇点开始,到另一个奇点结束)(欧拉通路
(2)对于有向图来说就是所有点的入度与出度都相等(欧拉回路)或者存在一个点入度比出度大一(终点),存在另一个点出度比入度大一(起点),其他点的入度与出度相等。(从起点开始,到终点结束)(欧拉通路

思路:
将每个单词的首、尾字母看成点,单词看成边,构成一个有向图

代码如下:
dfs

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn=100;
int n;
int G[maxn][maxn],vis[maxn],in[maxn],out[maxn];
void dfs(int u)
{
	vis[u]=1;        //访问标记
	for(int v=0;v<26;v++)     //字母节点
	if(!vis[v]&&G[u][v])
	dfs(v);           //没有被访问并且有有向边
}


int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		char s[100005];
		memset(vis,1,sizeof(vis));       //标志是否被遍历过
		memset(G,0,sizeof(G));
		memset(in,0,sizeof(in));         //入度
		memset(out,0,sizeof(out));       //出度
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%s",s);
			int len=strlen(s);
			int r=s[0]-'a';       //首
			int t=s[len-1]-'a';    //尾
			G[r][t]=1;              //有有向边
			in[t]++;
			out[r]++;          //很重要!!!,出入度别写反了,
			vis[r]=vis[t]=0;         //将其置为未访问状态
		}
		int flag=0,cnt1=0,cnt2=0,cnt3=0,p=0;
		for(int i=0;i<26;i++)
		{
			if(in[i]==out[i])        //环的情况
			continue;
			else if(out[i]==in[i]+1)     //起点
			{
				p=i;
				cnt1++;
			}
			else if(in[i]==out[i]+1)      //终点
			cnt2++;
			else cnt3++;   //没有满足
		}
		if(cnt3>0)
		{
			printf("The door cannot be opened.\n");
			continue;
		}
		if(cnt1==0&&cnt2==0 || cnt1==1&&cnt2==1)      //组成环或者一条直线
		flag=1;
		else flag=0;
		dfs(p);
		for(int i=0;i<26;i++)
		if(!vis[i]) flag=0;
		if(flag==1) printf("Ordering is possible.\n");
		else printf("The door cannot be opened.\n");
	}
	return 0;
}

并查集

#include<bits/stdc++.h>
using namespace std;
const int maxn=100;
const int inf=0x3f3f3f3f;
typedef long long ll;
int book[maxn],f[maxn],in[maxn],out[maxn];

int getf(int x)
{
    if(x==f[x])
        return x;
    return f[x]=getf(f[x]);
}

void mer(int u,int v)
{
    int t1=getf(u);
    int t2=getf(v);
    if(t1!=t2)
        f[t2]=t1;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        string s;
        int n;
        cin>>n;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(book,0,sizeof(book));
        for(int i=0;i<26;i++)
            f[i]=i;
        for(int i=0;i<n;i++)
        {
            cin>>s;
            mer(s[0]-'a',s[s.size()-1]-'a');
            out[s[0]-'a']++;
            in[s[s.size()-1]-'a']++;
            book[s[0]-'a']=book[s[s.size()-1]-'a']=1;
        }
        int a=0,b=0,ans=0,flag=1,mark=1;
        for(int i=0;i<26;i++)
        {
            if(book[i])
            {
                if(f[i]==i)
                    ans++;//只能有一个祖宗,即起点
                if(in[i]!=out[i])
                {
                    if(in[i]==out[i]+1)
                        a++;
                    else if(out[i]==in[i]+1)
                        b++;
                    else
                        mark=0;
                }
                if(ans>1||!mark)
                {
                    flag=0;
                    break;
                }
            }
        }
        if(flag&&mark)
        {
            if((!a&&!b)||(a==1&&b==1))
                cout<<"Ordering is possible."<<endl;
            else
                cout<<"The door cannot be opened."<<endl;
        }
        else
            cout<<"The door cannot be opened."<<endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值