[关闭]
@xingxing 2017-02-08T13:38:14.000000Z 字数 2252 阅读 914

专题五 拓扑排序/欧拉路

题解拓扑排序/欧拉路


[题目][A]

确定比赛名次

题目大意:

把N个队伍(1 <= N <= 500)按照M(0 <= M < 250000)个描述进行排名,让编号小的队伍尽量排在前面。
M描述如下:
P1 P2:P1赢了P2
有多个测试样例。

解题思路:

拓扑排序。利用kahn算法。
把队伍看做点,M所描述的关系为偏序关系,建立P1->P2的图,然后处理图,记下每个点的入度indegree[n]。找到入度为0的点然后压入优先队列(保证同一批的点按序号从小到大输出),然后优先级最高的出队,然后把从该点出发,有线段连接的端点的入度减一,然后再把入度为0的点压入优先队列。
时间复杂度O(n+m),空间复杂度O(1).

AC代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <functional>
  5. #include <vector>
  6. #include <cstdlib>
  7. #include <cstring>
  8. using namespace std;
  9. const int maxn = 500+5;
  10. int graph[maxn][maxn];
  11. int indegree[maxn];
  12. int n,m;
  13. struct cmp
  14. {
  15. bool operator () (int &a,int &b)
  16. {
  17. return a > b;
  18. }
  19. };
  20. //priority_queue<int,vector<int>,cmp> q;
  21. void toposort()
  22. {
  23. int i;
  24. int temp;
  25. int cnt = 0;
  26. priority_queue<int,vector<int>,greater<int> >q;
  27. while(!q.empty()) q.pop();
  28. for(i = 1;i <= n;i++)
  29. {
  30. if(indegree[i] == 0) q.push(i);
  31. }
  32. while(!q.empty())
  33. {
  34. temp = q.top();
  35. cnt++;
  36. if(cnt == 1) printf("%d",temp);
  37. else printf(" %d",temp);
  38. q.pop();
  39. for(i = 1; i <= n; i++)
  40. {
  41. if(graph[temp][i])
  42. {
  43. indegree[i]--;
  44. if(indegree[i] == 0)
  45. q.push(i);
  46. }
  47. }
  48. }
  49. printf("\n");
  50. }
  51. int main()
  52. {
  53. //freopen("in.txt","r",stdin);
  54. //freopen("out.txt","w",stdout);
  55. int a,b;
  56. int i,j;
  57. while(scanf("%d%d",&n,&m) != EOF)
  58. {
  59. memset(graph,0,sizeof(graph));
  60. memset(indegree,0,sizeof(indegree));
  61. for(i = 0;i < m;i++)
  62. {
  63. scanf("%d%d",&a,&b);
  64. graph[a][b] = 1;
  65. }
  66. for(i = 1;i <= n;i++)
  67. {
  68. for(j = 1;j <= n;j++)
  69. indegree[i] += graph[j][i];
  70. }
  71. toposort();
  72. }
  73. return 0;
  74. }

[题目][D]

欧拉回路

题目大意:

给出n个点(1 < n < 1000)和m条边(1 < m < 1e6),判断欧拉回路是否存在。
有多个测试样例,当n为0是输入结束。

解题思路:

无向欧拉图回路满足:
1、该图为连通图;
2、任一点的度数为偶数。
根据m条边的信息初始化图,保存每个点的度数到数组对应的位置,最后判断条件2.然后用bfs算法遍历图,根据最后遍历的标志量,来检查条件1.
时间复杂度O(m+n),空间复杂度O(1).

AC代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <queue>
  5. #include <cstdlib>
  6. using namespace std;
  7. int n,m;
  8. const int maxn = 1000+5;
  9. int graph[maxn][maxn];
  10. int degree[maxn];
  11. int bfs(int a)
  12. {
  13. int flag[maxn];
  14. int i,temp;
  15. queue<int> p;
  16. for(i = 1;i <= n;i++) flag[i] = 0;//!!!
  17. p.push(a);
  18. flag[a] = 1;
  19. while(!p.empty())
  20. {
  21. temp = p.front();
  22. p.pop();
  23. for(i = 1;i <= n;i++)
  24. {
  25. if(graph[temp][i] && flag[i] == 0)
  26. {
  27. p.push(i);
  28. flag[i] = 1;
  29. }
  30. }
  31. }
  32. for(i = 1;i <= n;i++)
  33. {
  34. if(flag[i] == 0) return 0;
  35. }
  36. return 1;
  37. }
  38. int main()
  39. {
  40. int i;
  41. int a,b;
  42. int sum;
  43. while(scanf("%d",&n) != EOF && n)
  44. {
  45. scanf("%d",&m);
  46. memset(graph,0,sizeof(graph));
  47. memset(degree,0,sizeof(degree));
  48. for(i = 0;i < m;i++)
  49. {
  50. scanf("%d%d",&a,&b);
  51. if(graph[a][b] == 0)
  52. {
  53. graph[a][b] = 1;
  54. graph[b][a] = 1;
  55. degree[a]++;
  56. degree[b]++;
  57. }
  58. }
  59. sum = 0;
  60. for(i = 1;i <= n;i++)
  61. {
  62. if(degree[i]% 2 == 1) sum++;
  63. }
  64. if(sum == 0 && bfs(a))
  65. printf("1\n");
  66. else
  67. printf("0\n");
  68. }
  69. return 0;
  70. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注