uva 10129 Play On Words(单词)求欧拉回路或欧拉通路

题目:输入n个单词,是否可以把这些所有单词排成一个序列,使得每个单词的第一个字母和上一个单词的最后一个字母想同。

有向图欧拉回路:1,图连通.2,所有定点入度等于出度

有向图欧拉通路:1,图连通.2,仅有两个奇度定点,其中一个入度比出度大1,另一个定点出度比入度大1


思路:可以把一个单词看作一条边,单词的首尾两个字母为定点,建立无向图(即G[u][v]=G[v][u]=1),因为欧拉回路和欧拉通路的条件都必须是连通图,也就是有向图的底图无向图必须是连通图。

可以用dfs来判断无向图是否连通,先从一个定点开始dfs,每访问一条边,就删除一条边,即G[u][v]--,G[v][u]--,最后判断所有定点是否被访问到,如果全部被访问到,则图连通,反之不连通。

接下来就是判断两个条件:

(1)所有定点入度等于出度

(2)仅有两个奇度定点,其中一个入度比出度大1,另一个定点出度比入度大1

只有当图连同,(1)和(2)有一个成立,就说明是欧拉回路或者欧拉通路。

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.Vector;

public class Main {

	static int maxn = 26;
	static int[][] G = new int[maxn][maxn];
	static int[] in = new int[maxn];
	static int[] out = new int[maxn];
	static boolean[] vis = new boolean[maxn];
	static int start;
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		int T = scan.nextInt();
		while(T--!=0){
			Arrays.fill(vis, false);
			Arrays.fill(in, 0);
			Arrays.fill(out, 0);
			Set<Integer> set = new HashSet<>();
			for(int i=0;i<maxn;i++){
				Arrays.fill(G[i], 0);
			}
			int n = scan.nextInt();
			for(int i=0;i<n;i++){
				String str = scan.next();
				int u = str.charAt(0)-'a';
				int v = str.charAt(str.length()-1)-'a';
				G[u][v]++;
				G[v][u]++;
				out[u]++;
				in[v]++;
				start = u;
			}
			//判断图是否连通
			dfs(start);
			boolean isDfs = true;
			for(int i=0;i<maxn;i++){
				if(in[i]+out[i]>0&&vis[i]==false){
					isDfs = false;
				}
			}
			boolean flag1=true,flag2=true;
			//判断是不是所有顶点入度等于出度
			for(int i=0;i<maxn;i++){
				if(in[i]!=out[i]){
					flag1 = false;
				}
			}
			Vector<Integer> v = new Vector<>();
			int cnt = 0;
			//判断是不是有两个奇度定点
			for(int i=0;i<maxn;i++){
				if((in[i]+out[i])%2!=0){
					v.add(i);
				}
				if(in[i]==out[i])cnt++;
			}
			if(v.size()!=2){
				flag2 = false;
			}else{
				int a = v.get(0);
				int b = v.get(1);
				if(!((in[a]-out[a]==1&&out[b]-in[b]==1)
						||(in[b]-out[b]==1&&out[a]-in[a]==1))){//看两个奇度顶点是不是满足有向图欧拉通路的条件
					flag2 = false;
				}
			}
			if(cnt!=24){
				flag2 = false;
			}
			
			if(isDfs){
				if(flag1||flag2){
					System.out.println("Ordering is possible.");
				}else{
					System.out.println("The door cannot be opened.");
				}
			}else{
				System.out.println("The door cannot be opened.");
			}
		}
	}
	
	public static void dfs(int u){
		vis[u] = true;
		for(int v=0;v<maxn;v++){
			if(G[u][v]>0){
				G[u][v]--;
				G[v][u]--;
				dfs(v);
			}
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值