1341 无序字母对

难度:提高+/省选-

题目类型:图论

提交次数:6

涉及知识:dfs/欧拉路径

题目描述

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

输入输出格式

输入格式:

第一行输入一个正整数n。

以下n行每行两个字母,表示这两个字母需要相邻。

输出格式:

输出满足要求的字符串。

如果没有满足要求的字符串,请输出“No Solution”。

如果有多种方案,请输出前面的字母的ASCII编码尽可能小的(字典序最小)的方案

输入输出样例

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

说明

【数据规模与约定】

不同的无序字母对个数有限,n的规模可以通过计算得到。

代码:

 1 #include<iostream>
 2 using namespace std;
 3 int n;
 4 const int N = 52;
 5 int map[60][60];
 6 int du[60];
 7 char ans[2500];
 8 bool flag;
 9 int change(char a){
10     int askii = (int)(a);
11     if(askii<97){
12         return askii-65;
13     }
14     else return askii-71;
15 }
16 char rechange(int x){
17     if(x<=25) return char(x+65);
18     else return char(x+71);
19 }
20 void dfs(int x, int step){    
21     ans[step] = rechange(x);
22     if(step==n+1){
23         flag = true;
24         return;
25     }
26     for(int i = 0; i < 52; i++){
27         if(map[x][i]>0){
28             map[x][i]--;
29             map[i][x]--;
30             dfs(i,step+1);    
31             if(flag) break;
32             map[x][i]++;
33             map[i][x]++;
34         }
35     }
36     if(!flag) ans[step] = 0;
37 }
38 int main(){
39     cin>>n;
40     int i;
41     for(i = 1; i <= n; i++){
42         char a, b;
43         cin>>a>>b;
44         int x = change(a);
45         int y = change(b);
46         map[x][y] = 1;
47         map[y][x] = 1;
48         du[x]++;
49         du[y]++;
50     }
51     int flag = 100;
52     int minn = 100;
53     int odd = 0;
54     for(i = 0; i <= 51; i++){
55         if(du[i]!=0&&minn==100) minn = i;
56         if(du[i]%2 == 1){
57             flag = min(flag, i);
58             odd++;
59         }
60             
61     }
62     if(odd!=0&&odd!=2) {
63         cout<<"No Solution"<<endl;
64         return 0;
65     }
66     if(flag!=100) dfs(flag, 1);
67     else dfs(minn,1);
68     for(i = 1; i <= n+1; i++){
69         cout<<ans[i];
70     }
71     cout<<endl;
72     return 0;
73 } 

备注:

欧拉路径就是一笔画,在图中仅有0或2个奇数入度点时存在。昨天下午看了半天求欧拉路径的算法,今天老师嘲讽一通说我看的是假的算法。。dfs+删边就可以了。虽然我很不愿意接受,但这么写写竟然是对的,而且效率还可以。

为什么是对的很简单。从一个奇数入度点出发,如果全是偶数入度点,就从最小的点开始,dfs,走到无路可走时就找到了一个解。注意一定要回溯(否则走入一条死胡同就结束了),肯定不能一到某个点就输出这个点(此时不一定走的就是正确的路)这也是dfs加一个step参量的必要性(最后一次更新一定是正解)(回溯到这个点说明上一次从这个点出去选择的方向走不完图,所以换个方向走)。

字典序很好办。从小到大搜就可以了。

后来codevs过了,洛谷最后一个点过不了。看了一眼讨论,发现ans数组开小了。n的规模可以算,应该是52*52,开成2500就过了。

原文地址:https://www.cnblogs.com/fangziyuan/p/6940742.html