标签:题意 include tps 连接 单词 ssi 操作 article push
题意:新定义题,重新定义了字典序的概念( 即 a不一定小于b),已的n个单词是按 新字典序 从小到大排序的,求重新定义字典序的字母顺序。如果先后有矛盾输出 “Impossible”。
思路:先把前缀一致的过滤,剩下将路径存入数组,并记录每个字母的入度;
最后拓扑排序:若是不按照26原始字母顺序来,可以直接先将入度为0的全部放入队列并记录答案p[t++],再对队列里的字母开始出队且删除与之有关的边,若删除后,那个字母的入度为0,则可进入队列,答案p[t++],若入度不为0,则不操作。最后若答案长度小于26,说明有环,否则成功输出p数组。
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 #include<stack> 5 #include <bitset> 6 #include<set> 7 #include<map> 8 #include<unordered_map> 9 #include<vector> 10 #include<cmath> 11 #include<string> 12 #include<string.h> 13 using namespace std; 14 typedef long long ll; 15 typedef pair<ll, int> pa; 16 typedef unsigned long long ull; 17 char s[105][105]; 18 int f[50], mapp[50][50], len[105]; 19 char p[1001];//存储拓扑排序结果; 20 void tp() { 21 int i, j, t = 0; 22 queue<int>q; 23 for (i = 0; i < 26; i++){//从小到大找出全部入度为0的字母 24 if (!f[i]){ 25 q.push(i); 26 p[t++] = i + ‘a‘; 27 } 28 } 29 while (!q.empty()){//进行拓扑排序 30 int k = q.front(); 31 q.pop(); 32 for (i = 0; i < 26; i++){ 33 if (mapp[k][i] == 1){ 34 f[i]--; 35 if (f[i] == 0){//直到入度为0才可以进去队列 36 q.push(i); 37 p[t++] = i + ‘a‘; 38 } 39 } 40 } 41 } 42 if (t < 26){ 43 printf("Impossible\n"); 44 } 45 else{ 46 p[t] = ‘\0‘; 47 printf("%s\n", p); 48 } 49 return; 50 } 51 52 int main() { 53 int n; 54 cin >> n; 55 for (int i = 0; i < n; i++) { 56 cin >> s[i]; 57 len[i] = strlen(s[i]); 58 } 59 int flag = 0; 60 for (int i = 0; i < n - 1; i++) { 61 int len1 = len[i]; 62 int len2 = len[i + 1]; 63 int lenm = min(len1, len2); 64 int k, a = 0; 65 //最多比较到较短的单词结束 66 for (k = 0; k < lenm; k++) { 67 if (s[i][k] != s[i+1][k]) { 68 a = 1; 69 if (!mapp[s[i][k] - ‘a‘][s[i+1][k] - ‘a‘]) {//没有出现过这两个字母的连接 70 mapp[s[i][k] - ‘a‘][s[i + 1][k] - ‘a‘] = 1; 71 f[s[i + 1][k] - ‘a‘]++; //入度+1,相当于在它前面还有一个字母 72 } 73 break; 74 } 75 } 76 if (!a) {//若是两个单词中某个是前缀必须是len1 77 if (k != len1) { 78 flag = 1; 79 break; 80 } 81 } 82 if (flag) { 83 break; 84 } 85 } 86 if (flag) { 87 printf("Impossible\n"); 88 } 89 else { 90 tp(); 91 } 92 return 0; 93 }
若是按照26字母原始顺序,则遍历每次取出第一个入度为0的字母,依次删除与之有关的边,入度为负记录答案num[cns++],再取出第一个入读为0的边,直到在26次循环中某一次没有找到入度为0的边,说明有环。代码参考:https://blog.csdn.net/qq_41890797/article/details/81742221
1 void tp() //拓扑排序的核心代码 2 { 3 int p,flag,cns=0; 4 for(int i=0; i<26; i++) 5 { 6 int flag=0; 7 for(int j=0; j<26; j++) 8 { 9 if(!f[j]) //此时这个字母是最小的 10 { 11 p=j; 12 flag=1; 13 break; 14 } 15 } 16 if(!flag) //没有可确定的字母,矛盾了 17 { 18 printf("Impossible\n"); 19 return; 20 } 21 f[p]--; 22 num[cns++]=p+‘a‘; 23 for(int j=0; j<26; j++) 24 if(map[p][j]) 25 f[j]--; //与p为前端的入度-1 26 } 27 num[cns]=0;//加 ‘/0’ 28 puts(num); 29 }
Fox And Names CodeForces - 510C
标签:题意 include tps 连接 单词 ssi 操作 article push
原文地址:https://www.cnblogs.com/0211ji/p/13443717.html