CRB and Roads
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 495 Accepted Submission(s): 225
Problem Description
There are N cities in Codeland.
The President of Codeland has a plan to construct one-way roads between them.
His plan is to construct M roads.
But CRB recognized that in this plan there are many redundant roads.
So he decided to report better plan without any redundant roads to President.
Help him!
The road (u, v) is redundant if and only if there exists a route from u to v without using it.
The President of Codeland has a plan to construct one-way roads between them.
His plan is to construct M roads.
But CRB recognized that in this plan there are many redundant roads.
So he decided to report better plan without any redundant roads to President.
Help him!
The road (u, v) is redundant if and only if there exists a route from u to v without using it.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains two integers N and M denoting the number of cities and the number of roads in the President’s plan.
Then M lines follow, each containing two integers u and v representing a one-way road from u to v.
1 ≤ T ≤ 20
1 ≤ N ≤ 2 * 104
1 ≤ M ≤ 105
1 ≤ u, v ≤ N
The given graph is acyclic, and there are neither multiple edges nor self loops.
The first line contains two integers N and M denoting the number of cities and the number of roads in the President’s plan.
Then M lines follow, each containing two integers u and v representing a one-way road from u to v.
1 ≤ T ≤ 20
1 ≤ N ≤ 2 * 104
1 ≤ M ≤ 105
1 ≤ u, v ≤ N
The given graph is acyclic, and there are neither multiple edges nor self loops.
Output
For each test case, output total number of redundant roads.
Sample Input
1
5 7
1 2
1 3
1 4
1 5
2 4
2 5
3 4
Sample Output
2
题意
给一个简单无环有向图,求出冗余边的个数。冗余边即若删去u->v,仍能从u走到v,这样的边就是一条冗余边。
分析
对于每个点,记录一下有哪些点可以到达这个点,由于是简单无环图,可以用拓扑排序搞定,拓扑排序的过程中记录下当前点的所有前驱点。然后,根据前驱点的拓扑序号,从大到小遍历维护更新这个可达矩阵,在更新之前先检查其前驱在这条边之前是否已可达当前点,是的话就说明是冗余边。
还有一个问题,用简单的二维数组当作矩阵来记录会超时的,所以我们使用bitset来记录可达状态,bitset[i][j]表示可从j点到达i点,这样更新时只用or一下,优化了时间。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<algorithm> #include<cstring> #include <queue> #include <vector> #include<bitset> using namespace std; typedef long long LL; const int mod = 772002+233; typedef pair<int,int> pii; #define X first #define Y second #define pb push_back //#define mp make_pair #define ms(a,b) memset(a,b,sizeof(a)) const int maxn = 2e4 + 10; vector<vector<int> > G,mp; int in[maxn]; int rec[maxn]; int top; int n, m; void topo() { top = 0; for (int i = 1;i <= n;++i) if (in[i] == 0) rec[top++] = i; for (int i = 0;i < top;++i) { int u = rec[i]; int Size = G[u].size(); for (int j = 0;j < Size;++j) { int v = G[u][j]; mp[v].push_back(u); //v的前驱结点u if (--in[v] == 0) rec[top++] = v; } } } bitset<maxn> bit[maxn]; int main(){ // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); int kase; cin >> kase; while(kase--) { cin >> n >> m; G.clear();G.resize(n + 2); mp.clear();mp.resize(n + 2); int u, v; memset(in, 0, sizeof(in)); for (int i = 1;i <= m;++i) { scanf("%d%d", &u, &v); G[u].push_back(v); in[v]++; } topo(); // for (int i = 0;i < top;++i) // cout << rec[i] << ' '; // cout << endl; for (int i = 0;i <= n;++i) { bit[i].reset(); bit[i].set(i); } int ans = 0; for (int i = 0;i < top;++i) { int u = rec[i]; // cout<<u<<endl; int Size = mp[u].size(); for (int j =Size-1;j >=0;--j) { int v = mp[u][j]; //v->u // printf("%d->%d ",v,u); if (bit[u][v]) ans++; //冗余 bit[u] |= bit[v];//能到达v的也能到达u } } cout << ans << endl; } return 0; }