No.18 - POJ1386 判断联通 找欧拉链

首先判断是否为联通图

非 联 通 图 谈 不 上 欧 拉 回 路 \red{非联通图谈不上欧拉回路}

欧拉链:

起始点,出度比入度多1
终止点,出度比入度少1
其他点,出度等于入度,所以出度加入度是偶数,满足欧拉回路规律。

c i n > > s t r i n g 非 常 慢 , 字 符 串 读 取 还 是 s c a n f ( " % s " ) 大 法 好 \orange{cin>>string非常慢,字符串读取还是scanf("\%s")大法好} cin>>stringscanf("%s")

// ShellDawn
// POJ1386
// No.18

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define MM(x) memset(x,0,sizeof(x))
using namespace std;

#define maxn 100005
int n;
int in[30];
int out[30];
char s[1005];
int E[maxn][2];
int fa[30];
int visited[30];
int ans;

int findfa(int x){
    int y = x;
    while(y != fa[y]) y = fa[y];
    int z = y;
    y = x;
    while(y != fa[y]){
        int t = fa[y];
        fa[y] = z;
        y = t;
    }
    return z;
}

void join(int x,int y){
    int fx = findfa(x);
    int fy = findfa(y);
    if(fx == fy) return ;
    if(fx > fy) swap(fx,fy);
    fa[fy] = fx;
    ans--;
}

bool connect(){
    for(int i=1;i<=26;i++) fa[i] = i;
    for(int i=0;i<n;i++){
        int a = E[i][0];
        int b = E[i][1];
        join(a,b);
        if(ans <= 1) return true;
    }
    return false;
}

int main(){
    int T;
    cin>>T;
    while(T--){
        ans = 0;
        MM(in);MM(out);MM(E);MM(visited);
        cin>>n;
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int a = s[0] - 'a' + 1;
            int b = s[strlen(s) - 1] - 'a' + 1;
            in[a] ++ ;
            out[b] ++ ;
            E[i][0] = a;
            E[i][1] = b;
            if(visited[a] == 0) visited[a] = 1,ans++;
            if(visited[b] == 0) visited[b] = 1,ans++;
        }
        bool flag = true;
        bool keyS = true;
        bool keyT = true;
        for(int i=1;i<=26;i++){
            if(in[i] == out[i]) continue;
            else{
                if(keyS && in[i] + 1 == out[i]) keyS = false;
                else if(keyT && in[i] - 1 == out[i]) keyT = false;
                else {
                    flag = false;
                    break;
                }
            }
        }
        if(flag && connect()) puts("Ordering is possible.");
        else puts("The door cannot be opened.");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值