首页 > 其他分享 >Uva--10129 Play On Words(欧拉路)

Uva--10129 Play On Words(欧拉路)

时间:2024-01-27 22:55:47浏览次数:32  
标签:Play startcnt start -- int 10129 endcnt situation out

记录
15:42 2023-5-26

reference:《算法竞赛入门经典第二版》例题6-16

把字母看作结点,单词看成有向边,则问题有解,当且仅当图中有欧拉路径。

有向图欧拉道路(回路)问题,有向图欧拉道路需要基图连通,且度数满足

最多只能有两个点的入度不等于出度,而且必须是其中一个点的出度恰好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点)。
判断基图连通的俩种方式:1.dfs 2.并查集

顺便说下,看的时候看了下《算法竞赛进阶指南》,这里面实现图的方式很有意思(哈哈,因为我没接触过,还是要打开思路

int head[N], ver[N], nxt[N], edge[N], tot;

/*
也就是模仿了邻接表的建立
原来的时候
head[x]表示x的第一条边的编号
ver[head[x]]=y
next[head[x]] 表示x的第一条边的下一条边的编号
head[x] -> x第一条边
那么 加入一条新的边就变成了
ver[++tot]=y
edge[tot]=z
next[tot] = head[x] //接管原来的第一条边 或者可以理解为此时next[tot] 和 head[x]指向同一个边
head[x] = tot //更新x的第一条边 也就是断开了原来的第一条边
*/
void add (int x, int y, int z) {
    ver[++tot] = y;
    edge[tot] = z;
    nxt[tot] = head[x];
    head[x] = tot;
}

写了这么多,其实需要记住head和next存的都是边的编号,ver数组的下标也是边的编号,这里建图的方式是类似于插头节点建图,所以后面来的边会先访问到。

dfs

#include<cstdio>
#include<iostream>
#include<sstream>
#include<memory.h>
#define MAX_N 100005
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;

int N;
int T;

int graph[30][30];
int vis[30][30];
int visit[30]; //1表示需要访问的点
int in[30], out[30];

void build_grapch(int v, int u) {
    graph[v][u] = 1;
}

void euler(int v) {
    for (int i = 0; i < 26; i++) {
        if (graph[v][i] && !vis[v][i]) {
            vis[v][i] = vis[i][v] = 1;
            euler(i);
        }
    }
}

void dfs(int v) {
    visit[v] = 0;
    for(int i = 0; i < 26; i++) {
        if(graph[v][i] && visit[i]) {
            dfs(i);
        }
    }
}

int main() {
    string str;
    cin >> T;
    // start、end分别表示欧拉路径的起点和终点,startcnt、endcnt表示度数为奇数的点的个数
    int start, end, startcnt, endcnt; 
    // situation 表示欧拉路径的情况,0表示无欧拉路径,1表示有欧拉路径,2表示有欧拉回路
    int situation;  
    while(T--) {
        start = end = startcnt = endcnt = 0;
        situation = 0;
        memset(graph, 0x00, sizeof(graph));
        memset(vis, 0x00, sizeof(vis));
        memset(visit, 0x00, sizeof(visit));
        memset(in, 0x00, sizeof(in));
        memset(out, 0x00, sizeof(out));
        cin >> N;
        for (int i = 0; i < N; i++) {
            cin >> str;
            int s = str[0] - 'a';
            int e = str[str.size() - 1] - 'a';
            build_grapch(s, e);
            out[s] += 1;
            in[e] += 1;
            //随便找一个start
            start = s;
            visit[s] = visit[e] = 1;
        }
        
        for(int i = 0; i < 26; i++) {
            if(out[i] - in[i] == 1) {
                start = i;
                startcnt += 1;
            } else if(in[i] - out[i] == 1){
                end = i;
                endcnt += 1;
            } else if(in[i] != out[i]) {
                startcnt = endcnt = -1; // 有度数为奇数的点,但是不是欧拉路径
            }

        }

        if ((startcnt == 0 && endcnt == 0) || (startcnt == 1 && endcnt == 1)) {
            if (startcnt == 1 && endcnt == 1)
                situation = 1;
            else 
                situation = 2;    
            
            dfs(start);
            for(int i = 0; i < 26; i++) {
                if(visit[i]) { 
                    situation = 0;
                    break;
                }
            }
  
        } else {
            situation = 0;
        }

        if (situation == 0) {
            printf("The door cannot be opened.\n");
        } else {
            printf("Ordering is possible.\n");
        }
    }
}

并查集

#include<cstdio>
#include<iostream>
#include<sstream>
#include<memory.h>
#define MAX_N 100005
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;

int N;
int T;

int in[30], out[30];

int is_exist[MAX_N]; //1表示这个字符存在
int par[MAX_N];
int rak[MAX_N];

int find(int x) {
    if(par[x] == x) {
        return x;
    } else {
        return par[x] = find(par[x]);
    }
}

void init_disjoint_set(int n) {
    for(int i = 0; i < n; i++) {
        par[i] = i;
        rak[i] = 0;
    }
}

void unite(int x, int y) {
    x = find(x);
    y = find(y);

    if(x == y) return;

    if(rak[x] < rak[y]) {
        par[x] = y;
    } else {
        par[y] = x;
        if(rak[x] == rak[y]) rak[x]++;
    }
}

int main() {
    string str;
    cin >> T;
    // start、end分别表示欧拉路径的起点和终点,startcnt、endcnt表示度数为奇数的点的个数
    int start, end, startcnt, endcnt; 
    // situation 表示欧拉路径的情况,0表示无欧拉路径,1表示有欧拉路径,2表示有欧拉回路
    int situation;  
    while(T--) {
        start = end = startcnt = endcnt = 0;
        situation = 0;
        memset(in, 0x00, sizeof(in));
        memset(out, 0x00, sizeof(out));
        memset(is_exist, 0x00, sizeof(is_exist));
        init_disjoint_set(26);
        cin >> N;
        for (int i = 0; i < N; i++) {
            cin >> str;
            int s = str[0] - 'a';
            int e = str[str.size() - 1] - 'a';

            unite(s, e);
            is_exist[s] = is_exist[e] = 1;

            out[s] += 1;
            in[e] += 1;
            //随便找一个start
            start = s;
        }
        
        for(int i = 0; i < 26; i++) {
            if(out[i] - in[i] == 1) {
                start = i;
                startcnt += 1;
            } else if(in[i] - out[i] == 1){
                end = i;
                endcnt += 1;
            } else if(in[i] != out[i]) {
                startcnt = endcnt = -1; // 有度数为奇数的点,但是不是欧拉路径
            }

        }

        if ((startcnt == 0 && endcnt == 0) || (startcnt == 1 && endcnt == 1)) {
            if (startcnt == 1 && endcnt == 1)
                situation = 1;
            else 
                situation = 2;    
            
            //找到第一个字符
            int root = find(start);

            for(int i = 0; i < 26; i++) {
                if(is_exist[i]) {
                    if(find(i) != root) {
                        situation = 0;
                        break;
                    }
                }
            }
  
        } else {
            situation = 0;
        }

        if (situation == 0) {
            printf("The door cannot be opened.\n");
        } else {
            printf("Ordering is possible.\n");
        }
    }
}

利用数组构造邻接表的dps(emm有点拗口)

#include<cstdio>
#include<iostream>
#include<sstream>
#include<memory.h>
#define MAX_N 1000005
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int INF = 0x3f3f3f3f;

int N;
int T;

int head[30], ver[MAX_N], nxt[MAX_N], total;  //邻接表
int visit[30]; //1表示需要访问的点
int in[30], out[30];

void add_edge(int x, int y) {
    ver[++total] = y;
    nxt[total] = head[x];
    head[x] = total;
}

void dfs(int x) {
    visit[x] = 0;
    for(int e = head[x]; e ; e = nxt[e]) {
        int i = ver[e];
        if (visit[i]) {
           dfs(i);
        }
    }
}

int main() {
    string str;
    cin >> T;
    // start、end分别表示欧拉路径的起点和终点,startcnt、endcnt表示度数为奇数的点的个数
    int start, end, startcnt, endcnt; 
    // situation 表示欧拉路径的情况,0表示无欧拉路径,1表示有欧拉路径,2表示有欧拉回路
    int situation;  
    while(T--) {
        start = end = startcnt = endcnt = 0;
        situation = 0;
        memset(head, 0x00, sizeof(head));
        memset(ver, 0x00, sizeof(ver));
        memset(nxt, 0x00, sizeof(nxt));
        total = 0;
        memset(visit, 0x00, sizeof(visit));
        memset(in, 0x00, sizeof(in));
        memset(out, 0x00, sizeof(out));
        cin >> N;
        for (int i = 0; i < N; i++) {
            cin >> str;
            int s = str[0] - 'a' + 1;  //从1开始
            int e = str[str.size() - 1] - 'a' + 1;
            add_edge(s, e);
            out[s] += 1;
            in[e] += 1;
            //随便找一个start
            start = s;
            visit[s] = visit[e] = 1;
        }
        
        for(int i = 1; i <= 26; i++) {
            if(out[i] - in[i] == 1) {
                start = i;
                startcnt += 1;
            } else if(in[i] - out[i] == 1){
                end = i;
                endcnt += 1;
            } else if(in[i] != out[i]) {
                startcnt = endcnt = -1; // 有度数为奇数的点,但是不是欧拉路径
            }

        }

        if ((startcnt == 0 && endcnt == 0) || (startcnt == 1 && endcnt == 1)) {
            if (startcnt == 1 && endcnt == 1)
                situation = 1;
            else 
                situation = 2;    
            
            dfs(start);
            for(int i = 1; i <= 26; i++) {
                if(visit[i]) { 
                    situation = 0;
                    break;
                }
            }
  
        } else {
            situation = 0;
        }

        if (situation == 0) {
            printf("The door cannot be opened.\n");
        } else {
            printf("Ordering is possible.\n");
        }
    }
}

标签:Play,startcnt,start,--,int,10129,endcnt,situation,out
From: https://www.cnblogs.com/57one/p/17992300

相关文章

  • 微客云霸王餐v2上线 自主招商+美团霸王餐 全面开跑
    、、、、大家好,微客云春节前最后一次重大更新,此次更新全部围绕本地生活方向进行,对现有功能进行了优化迭代,围绕霸王餐模块增加了关于新人的营销功能,包括新人补贴金、新人抽奖(免单券)、邀请挑战赛(全站)等,同时外卖CPS方向新增了超赞集合页面,美团14城霸王餐正式发布,废话不多说,看下面[gf......
  • 《程序是怎样跑起来的》第一章读后感
    首先读这本书看到开头列出了几个问题,我试着回答,但是无法用专业的语言来形容。在接触到计算机之前,道听途说再结合自己的理解,以下是我个人的回答,程序就是一系列的代码组合而成来执行一些“动作”的东西,机器语言这个名词在初学Java的时候老师简单介绍过,机器语言是针对特定型号计算机......
  • day25 代码随想录算法训练营 17. 电话号码的字母组合
    题目:17.电话号码的字母组合我的感悟:一时间没理解没关系,只要不放弃,就会成长!!!理解难点:index是独立集合的起点,需要理解它。有些东西就是时间的积累代码难点:代码示例:classSolution:def__init__(self):self.letterMap=["",#0......
  • 查看、清空Linux日志【系统日志、软件运行日志】
    一、各种系统日志文件位置123456789101112131415/var/log/messages:记录Linux内核消息及各种应用程序的公共日志信息 /var/log/cron:      记录crond计划任务产生的事件信息 /var/log/dmesg:     记录Linux操作系统在引导过程......
  • AtCoder Beginner Contest 338
    AtCoderBeginnerContest338ABC切ABC,什么实力。C-LeftoverRecipesProblemStatementYourrefrigeratorhas\(N\)kindsofingredients.Letuscallthemingredient\(1\),\(\dots\),ingredient\(N\).Youhave\(Q_i\)gramsofingredient\(i\).......
  • 初中英语优秀范文100篇-071Changes in my school-我的学校发生的变化
    PDF格式公众号回复关键字:SHCZFW071记忆树1Whentalkingaboutourschool,weusuallyhavealottosay,includingtheteachers,thestudentsandsoon.翻译当谈论我们的学校时,我们通常有很多话要说,包括老师、学生等等。简化记忆谈论句子结构主语:we谓语:have宾......
  • R语言KNN模型分类信贷用户信用等级参数调优和预测可视化
    全文链接:https://tecdat.cn/?p=34941原文出处:拓端数据部落公众号本文主要介绍了如何帮助客户通过读取数据、查看部分数据、转换数据为因子并将数值变量归一化、进行描述性分析、建立knn模型等步骤对数据进行分析。通过分别选择不同的k值进行建模,并对比它们的准确度,找到最优的参......
  • for (オプション) %%アルファベット1文字 in (ループ処理の対象) do コマンド
    for(オプション)%%アルファベット1文字in(ループ処理の対象)doコマンド转载自:https://qiita.com/plcherrim/items/67be34bab1fdf3fb87f9#4トークンオプション-usebackq-標準型for(オプション)%%アルファベット1文字in(ループ処理の対象)doコマンド(オプション無し)デ......
  • PYTHON用时变马尔可夫区制转换(MARKOV REGIME SWITCHING)自回归模型分析经济时间序列|附
    全文下载链接:http://tecdat.cn/?p=22617最近我们被客户要求撰写关于MRS的研究报告,包括一些图形和统计输出。本文提供了一个在统计模型中使用马可夫转换模型模型的例子,来复现Kim和Nelson(1999)中提出的一些结果。它应用了Hamilton(1989)的滤波器和Kim(1994)的平滑器  %matplot......
  • 为什么使用交叉熵作为逻辑回归的损失函数?
    整理以前学习过程中的疑问。为什么使用交叉熵作为逻辑回归的损失函数?频率学派的一种估计参数的方法,这种方法适合分类回归任务。必须要提一下的是,频率学派将参数\(\theta\)​看作一个未知待估计的常数,其目标是使用带一定性质的估计方法求出。似然函数就是其中的一种方法。A......