[关闭]
@wsndy-xx 2018-05-20T10:48:25.000000Z 字数 1259 阅读 930

Luogu 兽径管理

题解


数组开小没察觉,挂掉好几遍

题意肯定是求最小生成树了,问题在于怎样减少时间消耗。

主要思路是逆序求解,因为这样可以尽可能地减少使用Kruskal的次数,时间复杂度自然就降下来了

每次Kruskal记录用到的边,如果(每一周)删掉了一条用到的边,那自然需要重新求一遍最小生成树;如果没用到,那就不用求了,直接赋值为上一个结果。

如果有一周出现了-1,那它继续删边肯定更不联通了,所以之后所有答案都是-1,break就好


Code

  1. #include <bits/stdc++.h>
  2. const int N = 210;
  3. const int M = 6010;
  4. long long Answer[M];
  5. int fa[N], n, m, nowid;
  6. struct Node {
  7. int u, v, w, day;
  8. bool operator < (const Node &a) const {
  9. return w < a.w;
  10. }
  11. } E[M << 1];
  12. bool Be_use[M << 1];
  13. #define gc getchar()
  14. inline int read() {
  15. int x = 0, f = 1; char c = gc;
  16. while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc;}
  17. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
  18. return x * f;
  19. }
  20. int Get_fa(int x) {return x == fa[x] ? x : fa[x] = Get_fa(fa[x]);}
  21. long long Work() {
  22. memset(Be_use, 0, sizeof Be_use);
  23. for(int i = 1; i <= n; i ++) fa[i] = i;
  24. long long js(0), ret(0);
  25. for(int i = 1; i <= m; i ++) {
  26. if(E[i].day > nowid) continue ;
  27. int a = E[i].u, b = E[i].v, fa_a = Get_fa(a), fa_b = Get_fa(b);
  28. if(fa_a != fa_b) js ++, ret += E[i].w, fa[fa_a] = fa_b, Be_use[E[i].day]= 1;
  29. if(js == n - 1) break;
  30. }
  31. if(js != n - 1) return -1;
  32. return ret;
  33. }
  34. int main() {
  35. n = read(), m = read();
  36. for(int i = 1; i <= m; i ++) E[i].u = read(), E[i].v = read(), E[i].w = read(), E[i].day = i;
  37. std:: sort(E + 1, E + m + 1);
  38. nowid = m;
  39. Answer[m] = Work();
  40. for(int i = m - 1; i >= 1; i --) {
  41. if(Be_use[i + 1]) nowid = i, Answer[i] = Work();
  42. else Answer[i] = Answer[i + 1];
  43. if(Answer[i] == -1) {
  44. for(int j = 1; j < i; j ++) Answer[j] = -1;
  45. break;
  46. }
  47. }
  48. for(int i = 1; i <= m; i ++) std:: cout << Answer[i] << "\n";
  49. return 0;
  50. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注