https://vjudge.net/problem/UVALive-7272
题意:
公司要提拔人,现在有n个人,现在有m条有向边,A->B表示A的表现比B好,也就是如果B晋升了,那么A肯定会晋升。
现在给出【L,R】,计算出晋升L个人时肯定会晋升的人数,晋升R个人时肯定会晋升的人数,还有肯定不可能晋升的人数。
思路:
先说一下计算不可能人数的算法。
这个需要反向建图,我们dfs遍历,假设现在从第i个人开始遍历,遍历得到它的子节点的个数,这就是说如果i晋升的话,他前面的人也都必须要晋升。
如果这个人数大于了限定的晋升人数,那么这个人肯定是不可能晋升的。
剩余两个也是这样分析的,具体参见代码。
1 #include<iostream> 2 #include<string> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cstdio> 7 using namespace std; 8 9 const int maxn=5000+5; 10 11 int n, m; 12 int A,B; 13 int num; 14 15 vector<int> g[maxn]; 16 vector<int> r_g[maxn]; 17 18 int vis[maxn]; 19 20 void r_dfs (int u) 21 { 22 if(vis[u]) return; 23 vis[u]=1; 24 num++; 25 for(int i=0;i<r_g[u].size();i++) 26 { 27 r_dfs(r_g[u][i]); 28 } 29 } 30 31 32 void dfs (int u) 33 { 34 if(vis[u]) return; 35 vis[u]=1; 36 num++; 37 for(int i=0;i<g[u].size();i++) 38 { 39 dfs(g[u][i]); 40 } 41 } 42 43 int main() 44 { 45 //freopen("D:\input.txt", "r", stdin); 46 while (~scanf("%d%d%d%d",&A, &B, &n, &m)) 47 { 48 for(int i=0;i<n;i++) {g[i].clear();r_g[i].clear();} 49 for(int i=0;i<m;i++) 50 { 51 int u,v; 52 scanf("%d%d",&u,&v); 53 g[u].push_back(v); 54 r_g[v].push_back(u); 55 } 56 int ans1=0,ans2=0,ans3=0; 57 for(int i=0;i<n;i++) 58 { 59 memset(vis,0,sizeof(vis)); 60 num=-1; 61 r_dfs(i); 62 if(num>=B) ans3++; 63 memset(vis,0,sizeof(vis)); 64 num=-1; 65 dfs(i); 66 if(num>=n-A) ans1++; 67 if(num>=n-B) ans2++; 68 } 69 printf("%d %d %d ",ans1,ans2,ans3); 70 } 71 return 0; 72 }