[关闭]
@Asuna 2017-02-23T05:29:47.000000Z 字数 2258 阅读 660

2016寒假集训队第五次作业

题解


Problem A:确定比赛名次

题意:判断入度为0的点的个数是否唯一。

题解:拓扑排序:
  (1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它。
  (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边。
  (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止。
  
参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. int ans[510][510],n,in[510],queue[510],a,b,m,top,k;
  6. int main()
  7. {
  8. while (cin>>n>>m)
  9. {
  10. top=0;
  11. k=0;
  12. memset(in,0,sizeof(in));
  13. memset(ans,0,sizeof(ans));
  14. for (int i=0; i<m; i++)
  15. {
  16. cin>>a>>b;
  17. if(ans[a][b]==0)
  18. {
  19. ans[a][b]=1;
  20. in[b]++;
  21. }
  22. }
  23. for (int j=0; j<n; j++)
  24. {
  25. for (int i=1; i<=n; i++)
  26. {
  27. if (in[i]==0)
  28. {
  29. top=i;
  30. break;
  31. }
  32. }
  33. queue[k]=top;
  34. k++;
  35. in[top]=-1;
  36. for (int i=1; i<=n; i++)
  37. {
  38. if (ans[top][i])
  39. in[i]--;
  40. }
  41. }
  42. for (int i=0; i<k-1; i++)
  43. cout<<queue[i]<<" ";
  44. cout<<queue[n-1]<<endl;
  45. }
  46. return 0;
  47. }

Problem B:Reward

题意:n个人,m条边,每条边a,b 表示a比b的工资多1,每个人的工资至少888,问你工资和至少多少?如果出现矛盾关系,输出-1。

题解:根据人的工资关系建立拓扑图,工资尽量从888开始,然后根据是否能全部排好序判断是出现矛盾关系。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<queue>
  5. #include<vector>
  6. using namespace std;
  7. int n,m,ans[10010],r[10010],s,d,sum,a,b;
  8. vector <vector <int> > v;
  9. int main()
  10. {
  11. while(cin>>n>>m)
  12. {
  13. v.clear();
  14. v.resize(n+1);
  15. for (int i=0; i<=n; i++)
  16. {
  17. ans[i]=-1;
  18. r[i]=0;
  19. }
  20. while (m>0)
  21. {
  22. m--;
  23. cin>>a>>b;
  24. v[b].push_back(a);
  25. r[a]++;
  26. }
  27. queue <int> q;
  28. for (int i=1; i<=n; i++)
  29. {
  30. if(r[i]==0) q.push(i);
  31. }
  32. int tmp=888;
  33. while (!q.empty())
  34. {
  35. int l=q.size();
  36. while (l>0)
  37. {
  38. l--;
  39. s=q.front();
  40. q.pop();
  41. ans[s]=tmp;
  42. for (int i=0; i<v[s].size(); i++)
  43. {
  44. d=v[s][i];
  45. r[d]--;
  46. if (r[d]==0) q.push(d);
  47. }
  48. }
  49. tmp++;
  50. }
  51. sum=0;
  52. for (int i=1; i<=n; i++)
  53. {
  54. if (ans[i]>0) sum+=ans[i];
  55. else
  56. {
  57. sum=-1;
  58. break;
  59. }
  60. }
  61. cout<<sum<<endl;
  62. }
  63. return 0;
  64. }

Problem D:欧拉回路

题意:欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?若欧拉回路存在则输出1,否则输出0。

题解:由题意可知,这是一个无向图,无向图存在欧拉回路需要满足两个条件:
  1:底图是连通的,可用并查集判断。
  2:不存在度数为奇数的点。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<cmath>
  6. #include<algorithm>
  7. using namespace std;
  8. int a[1100],fa[1100],e,v;
  9. int find(int x)
  10. {
  11. if (x==fa[x]) return x;
  12. else
  13. {
  14. int r=find(fa[x]);
  15. fa[x]=r;
  16. return r;
  17. }
  18. }
  19. void join(int x, int y)
  20. {
  21. int fx=find(x),fy=find(y);
  22. if (fx!=fy) fa[fx]=fy;
  23. }
  24. int iseuler()
  25. {
  26. for (int i=1; i<=v; i++)
  27. if (a[i]&1) return 0;
  28. return 1;
  29. }
  30. int isConnct()
  31. {
  32. int cnt=0;
  33. for (int i=1; i<=v; i++)
  34. if (fa[i]==i) cnt++;
  35. if (cnt==1) return 1;
  36. return 0;
  37. }
  38. int main()
  39. {
  40. while(cin>>v)
  41. {
  42. if (v==0) break;
  43. cin>>e;
  44. memset(a,0,sizeof(a));
  45. for (int i=1; i<=1010; i++)
  46. fa[i]=i;
  47. for (int i=1; i<=e; i++)
  48. {
  49. int from,to;
  50. cin>>from>>to;
  51. a[from]++;
  52. a[to]++;
  53. join(from,to);
  54. }
  55. //cout<<11111<<endl;
  56. if (isConnct() && iseuler()) cout<<"1"<<endl;
  57. else cout<<"0"<<endl;
  58. }
  59. return 0;
  60. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注