无序字母对 - C++

无序字母对

题目描述
给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒)。请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现。

输入格式 
       第一行输入一个正整数n。
       以下n行每行两个字母,表示这两个字母需要相邻。
输出格式 输出满足要求的字符串。
如果没有满足要求的字符串,请输出“No Solution”。
如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

输入输出样例  
 输入 #1 
    4
    aZ
    tZ
    Xt
    aX
    
 输出 #1 
    XaZtX

这道题一开始就没什么思路,因为根本不会联想到图。但这是图的遍历里面出现的题,就觉得事情不简单。果不其然,这里涉及到一个叫欧拉路的问题,为此我特地去了解了一下欧拉路系列知识。其实理解也不难。

如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
如果一个回路是欧拉路径,则称为欧拉回路。
具有欧拉回路的图称为欧拉图(简称E图)。具有欧拉路径但不具有欧拉回路的图称为半欧拉图。

通俗点理解就是,你遍历一个图每条边只遍历一次便是欧拉路径。每条边只遍历两次便是欧拉回路。这里还涉及到一个奇点问题,度数为奇数的点。要形成欧拉回路,要么是0个奇点,要么是2个奇点。0个奇点便是一个连通图,必然是有欧拉路径,而2个奇点便是类似一条链,出点和终点度必须为1,也就是起点终点有向边数必须为1,其余点的有向边边数为2,便形成一个欧拉回路。

再回到此题,你必须先判断是否能形成欧拉回路,若不能则输出“No Solution”。判断条件有以下;
首先可以判断奇点大于0,并且奇点不等于2,则不能形成欧拉回路。
用并查集查询祖先,若祖先不为1,这不能形成欧拉回路。
其次奇点等于2,则是类似链式回路。
奇点等于0,则是连通图。

若能形成欧拉回路,则把最小字典排序顶点字符作为第一个顶点,然后进行dfs,往后遍历即可。
C++代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m;
char a[2];
int dis[150];
int e[150][150];
int f[150];
int ans[1500],t;
int getf(int u)
{
    if(u != f[u])
    {
      f[u] = getf(f[u]);
      return f[u];
    }else
    return u;
}
void merge(int u,int v)
{
   int t1,t2;
   t1 = getf(u);
   t2 = getf(v);
   if(t1 != t2)
   f[t2] = t1; 
}

void dfs(int u)
{
    for(int i = 65; i < 150; i ++)
    {
      if(e[u][i])
      {
         e[u][i] = 0;
     e[i][u] = 0;
     dfs(i); 
  }
    }
   ans[t++] = u; 
}
int main()
{
   cin >> n;
   //f数组初始化
   for(int i = 1; i < 150; i ++)
   f[i] = i; 
   for(int i = 1; i <= n; i ++)
   {
    cin >> a;
    dis[a[0]] ++;
    dis[a[1]] ++;
    e[a[0]][a[1]] = 1;
    e[a[1]][a[0]] = 1;
    merge(a[0],a[1]);
   }
int cnt = 0,head = 0;
   //先判断是否是个连通图 
   for(int i = 65; i < 150; i ++)
   {
    //说明有祖先 
    if(f[i] == i && dis[i])
    cnt ++;
   }
   //说明不是一个连通图,可能多个子图 
   if(cnt != 1)
   {
    printf("No Solution");
    return 0;
   }
   cnt = 0;
   for(int i = 65; i < 150; i ++)
   {
     if(dis[i] % 2)
       {
        cnt ++;
        if(head == 0)
        head = i;
       }
   }
   //只有0个奇数度或两个奇数度才可行 
   if(cnt && cnt != 2)
   {
    printf("No Solution");
    return 0;
   }
   //0个奇数度 说明是个连通图 
   if(head == 0)
   for(int i = 65; i < 150; i ++)
   {
    if(dis[i])
    {
       head = i;
       break;
    }
   }
   dfs(head);
   for(int i = t - 1; i >= 0; i --)
   cout << char(ans[i]);
   return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
无序单链表的去重操作可以使用哈希表来实现。具体步骤如下: 1. 定义一个哈希表,用于记录链表已经出现过的元素。 2. 遍历链表节点,对于每个节点,首先在哈希表查找该节点的值是否存在。 3. 如果哈希表已存在该值,则说明链表已经有相同的元素,将该节点从链表删除;如果哈希表不存在该值,则将该值添加到哈希表,继续遍历下一个节点。 4. 最终,遍历完整个链表后,链表的重复元素都已经被删除。 具体实现的代码如下所示: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构 struct ListNode { int val; struct ListNode* next; }; void removeDuplicates(struct ListNode* head) { if (head == NULL) { return; } // 定义哈希表 int hashSet[1000] = {0}; struct ListNode* pre = head; struct ListNode* cur = head->next; // 遍历链表节点 while (cur != NULL) { // 如果哈希表已存在该值,则删除当前节点 if (hashSet[cur->val] != 0) { pre->next = cur->next; free(cur); cur = pre->next; } else { // 否则将该值添加到哈希表 hashSet[cur->val] = 1; pre = cur; cur = cur->next; } } } // 创建一个链表节点 struct ListNode* createNode(int val) { struct ListNode* node = (struct ListNode*)malloc(sizeof(struct ListNode)); node->val = val; node->next = NULL; return node; } // 打印链表 void printList(struct ListNode* head) { struct ListNode* cur = head; while (cur != NULL) { printf("%d ", cur->val); cur = cur->next; } printf("\n"); } int main() { // 创建链表示例:1->2->3->2->4->3 struct ListNode* head = createNode(1); head->next = createNode(2); head->next->next = createNode(3); head->next->next->next = createNode(2); head->next->next->next->next = createNode(4); head->next->next->next->next->next = createNode(3); printf("原始链表:"); printList(head); removeDuplicates(head); printf("去重后的链表:"); printList(head); return 0; } ``` 以上代码就可以实现对无序单链表进行去重操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值