CSU 1802 小X的战斗力【拓扑dp】
题意:n个人,每个人有一个能力值。给出m组关系A, B, 表示A的能力值大于B的能力值。
问:m组关系中是否有自相矛盾的?若不矛盾,问:第1个人在所有人的能力值中排名第几?有多少人的能力值的排名可以确定?
题解:拓扑排序。存两个图,原图与反图。
若原图可达该点数+反图可达该点数-1 = n,则排名确定。
bitset一下。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define X first 4 #define Y second 5 #define pii pair<int, int> 6 #define mp make_pair 7 typedef long long ll; 8 9 vector<int> ve[155], rve[155]; 10 int in[155], rin[155]; 11 bitset<155> dp[155], rdp[155]; 12 int ra[155], rra[155]; 13 int topsort(int n, int* in, vector<int>* ve, bitset<155>* dp, int* ra){ 14 queue<int> Q; 15 for(int i = 1; i <= n; i++) 16 if(in[i] == 0) Q.push(i); 17 int ret = 0; 18 while(!Q.empty()){ 19 int p = Q.front(); 20 Q.pop(); 21 ret++; 22 ra[p] = ret; 23 for(int i = 0; i < ve[p].size(); i++){ 24 int to = ve[p][i]; 25 in[to]--; 26 dp[to] |= dp[p]; 27 if( !in[to] ) Q.push(to); 28 } 29 } 30 return ret == n; 31 } 32 void debug(int n){ 33 puts("*******************"); 34 for(int i = 1; i <= n; i++){ 35 cout << i << endl; 36 cout << dp[i] << ' ' << rdp[i] << endl; 37 } 38 puts("********end********"); 39 } 40 int main(){ 41 int t; scanf("%d", &t); 42 while(t--){ 43 int n, m, u, v; 44 scanf("%d%d", &n, &m); 45 for(int i = 1; i <= n; i++){ 46 ve[i].clear(); 47 rve[i].clear(); 48 in[i] = rin[i] = 0; 49 ra[i] = rra[i] = 0; 50 dp[i].reset(), rdp[i].reset(); 51 dp[i][i-1] = rdp[i][i-1] = 1; 52 } 53 for(int i = 0; i < m; i++){ 54 scanf("%d%d", &u, &v); 55 ve[u].push_back(v); 56 in[v]++; 57 rve[v].push_back(u); 58 rin[u]++; 59 } 60 61 if( !topsort(n, in, ve, dp, ra) )//有向图有环 62 puts("Wrong"); 63 else{ 64 topsort(n, rin, rve, rdp, rra); 65 //前面有 dp[i]-1 个, 后面有 rdp[i]-1 个; 66 printf("%d\n", dp[1].count()+rdp[1].count()-1 == n? ra[1]:-1); 67 int sum = 0; 68 for(int i = 1; i <= n; i++) 69 if(dp[i].count()+rdp[i].count()-1 == n) sum++; 70 printf("%d\n", sum); 71 } 72 } 73 return 0; 74 }
另解:floyd
诸神对凡人心生艳羡,厌倦天堂。