[关闭]
@Pinetrie 2019-02-15T17:52:01.000000Z 字数 1857 阅读 1146

H - Subway Pursuit CodeForces - 1039B

题意:n个点m条边的有向图中,需要反向一些边使得图中无环。求这些需要反向的边中最小的边权值及需要反向的边的序号。

题解:不断二分答案然后判断是否有环,如果无环则增大答案,否则减小答案。判断是否有环可以用拓扑排序。在拓扑排序的过程中可以根据边的拓扑序来判断该边是否需要反转。对于边权值小于mid的边,由于这种边的方向是任意的,所以对于判断图是否有环不影响,拓扑排序的时候不需要加入这种边。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 100010;
  4. int n,m,tot,num,du[maxn],rak[maxn];
  5. vector<int>ed[maxn]; //拓扑排序的边集
  6. vector<int>ans; //反向的边集
  7. struct edge
  8. {
  9. int u,v,w;
  10. }edg[maxn];
  11. void topsort()
  12. {
  13. tot = 0;
  14. queue<int>Q;
  15. for(int i = 1;i <= n;i++)
  16. {
  17. if(du[i] == 0)
  18. {
  19. rak[i] = ++tot;
  20. Q.push(i);
  21. }
  22. }
  23. while(!Q.empty())
  24. {
  25. int i = Q.front();
  26. Q.pop();
  27. for(int j = 0;j < ed[i].size();j++)
  28. {
  29. du[ed[i][j]]--;
  30. if(du[ed[i][j]] == 0)
  31. {
  32. rak[ed[i][j]] = ++tot;
  33. Q.push(ed[i][j]);
  34. }
  35. }
  36. }
  37. }
  38. bool OK(int mid)
  39. {
  40. memset(du,0,sizeof(du));
  41. for(int i = 0;i < maxn;i++) ed[i].clear();
  42. for(int i = 1;i <= m;i++)
  43. {
  44. if(edg[i].w > mid)
  45. {
  46. ed[edg[i].u].push_back(edg[i].v);
  47. du[edg[i].v]++;
  48. }
  49. }
  50. topsort();
  51. for(int i = 1;i <= n;i++)
  52. {
  53. if(du[i] > 0) return false; //判断是否有环
  54. }
  55. ans.clear();
  56. for(int i = 1;i <= m;i++)
  57. {
  58. if(edg[i].w <= mid && rak[edg[i].u] > rak[edg[i].v]) //如果边的拓扑序与原来相反则这个边需要反向
  59. {
  60. ans.push_back(i);
  61. }
  62. }
  63. return true;
  64. }
  65. int main()
  66. {
  67. scanf("%d %d",&n,&m);
  68. for(int i = 1;i <= m;i++)
  69. {
  70. scanf("%d %d %d",&edg[i].u,&edg[i].v,&edg[i].w);
  71. }
  72. int l = 0,r = 1e9,mid;
  73. while(l <= r)
  74. {
  75. mid = (l + r) / 2;
  76. if(OK(mid))
  77. {
  78. num = mid;
  79. r = mid - 1;
  80. }
  81. else
  82. {
  83. l = mid + 1;
  84. }
  85. }
  86. printf("%d %d\n",num,ans.size());
  87. for(int i = 0;i < ans.size();i++)
  88. {
  89. printf("%d ",ans[i]);
  90. }
  91. printf("\n");
  92. return 0;
  93. }

H - Subway Pursuit CodeForces - 1039B

题意:在一[1,n]内查找一个点,每次可以询问该点是否在区间内,返回YES或者NO。每次询问后该点会移动0~k步。最多询问4500次,要求找到这个点。

题解:不断二分区间,每次在区间内随机选择一个数询问。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. ll n,k,flag;
  5. string s;
  6. bool OK(ll l,ll r)
  7. {
  8. printf("%lld %lld\n",l,r);
  9. cin>>s;
  10. if(s[0] == 'N') return false;
  11. else if(s[0] == 'Y')
  12. {
  13. if(l == r) flag = 1;
  14. return true;
  15. }
  16. }
  17. int main()
  18. {
  19. srand(time(NULL));
  20. cin>>n>>k;
  21. ll l,r,mid;
  22. l = 1,r = n;
  23. while(1)
  24. {
  25. mid = (l + r) / 2;
  26. if(OK(l,mid))
  27. {
  28. r = mid;
  29. if(flag) break;
  30. }
  31. else
  32. {
  33. l = mid + 1;
  34. }
  35. l = max((ll)1,l - k);
  36. r = min(n,r + k);
  37. mid = rand() % (r - l + 1) + l;
  38. OK(mid,mid);
  39. if(flag) break;
  40. l = max((ll)1,l - k);
  41. r = min(n,r + k);
  42. }
  43. return 0;
  44. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注