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 }
View Code

 另解:floyd

posted @ 2016-10-21 23:40  我在地狱  阅读(148)  评论(0编辑  收藏  举报