这篇题解没有用拓补排序 (嗐 菜就直说)c++
我的感受这道题拓补排序没有变种\(Floyd\)好写吧,思惟难度也低一点(亲眼目击机房dalao这道题拓补排序调了好久)。数组
对于这道题为何能够用\(Floyd\),应该就是传递性了。当\(A>B\)时,\(B>C\),那么如今确定有\(A>C\)了,想一想原来的\(Floyd\),是否是也有点传递性的味道。这样一来,咱们就能够在已知一部分条件的状况下,求出其余值的大小关系,最后看是否是每一个数都跟其余的每个数确认了关系,若是是,那么这个数的位置也就出来了,也就是排好序了,不是,就输入下一个数,直到知足每一个数都跟其余的每个数确认了关系。若是仍是不能很好理解的话,能够看下代码来理解。优化
具体代码里面有两个能够优化的地方,可是数据太水,不加也能过。spa
#include <bits/stdc++.h> using namespace std; int n , m , T; int dis[30][30]; int id(char x){ //字母转化为数字 return x - 'A' + 1; } int main(){ cin >> n >> m; T = m; for(int i = 1; i <= n; i++) dis[i][i] = 1; //这里统一认为本身大于本身(方便一点) while(T--){ char a , b , c; cin >> a >> b >> c; if(dis[id(a)][id(c)]){ //处理矛盾 printf("Inconsistency found after %d relations." , m - T); return 0; } dis[id(c)][id(a)] = 1; //c大于a for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dis[i][j] = dis[i][j] || (dis[i][k] && dis[k][j]); //变种Floyd i>j和i>k>j均可以代表i>j /* for(int i = 1; i <= n; i++) 上面的那个Floyd能够这样优化,由于咱们每次只涉及到了a和c,因此只用它们两个更新其余的就可 for(int j = 1; j <= n; j++) dis[i][j] = dis[i][j] || (dis[i][id(a)] && dis[id(a)][j]); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) dis[i][j] = dis[i][j] || (dis[i][id(c)] && dis[id(c)][j]); */ int f = 1; for(int i = 1; i <= n; i++){ int x = 0; for(int j = 1; j <= n; j++) if(dis[i][j] || dis[j][i]) x++; //若是肯定了与其余n个数(包括本身)的关系,那么就能够肯定这个数的位置 if(x != n) f = 0; } if(f){ printf("Sorted sequence determined after %d relations: " , m - T); for(int k = 1; k <= n; k++){ //这里应该也能优化,设立一个vis数组,存储当前这个数的位置,若是这个数字的位置早肯定了,那么就不算这个数,直接算下一个数 ,具体优化操做不想写了, 原谅个人懒惰T_T for(int i = 1; i <= n; i++){ int x = 0; for(int j = 1; j <= n; j++) if(dis[i][j]) x++; //最小的数只会大于一个数(它本身),第二小的数只会会大于两个数,以此类推 if(x == k) cout << (char)(i + 'A' - 1); //若是符合当前的排名,输出 } } cout << "."; //记得这个句号(6泪) return 0; } } printf("Sorted sequence cannot be determined."); return 0; }
双倍经验时间:code
P2419排序