• 见面礼——图论


    给定一个 n 个点 n 条边的无向图,你需要求有多少种选择图上的一个点 p 和一条边 (x,y) 的方案,使得删去 (x,y) 后图变成一棵树,且这棵树以 p 为根时每个节点的儿子个数均不超过 3。保证至少存在一种这样的方案。

    Input
    输入的第一行一个整数 n(2≤n≤105) 表示节点数,接下来 n 行每行两个整数 x,y(1≤x,y≤n) 描述图上的一条边。保证图中没有重边自环。

    Output
    输出一行一个正整数表示答案。

    Input
    6
    1 2
    1 3
    1 4
    1 5
    1 6
    2 3

    Output
    10

    解析:

    n个点n条边,所以该图就成一个环。只有将环中的一条边删去,该图才能变为一棵树。

    1. #include <bits/stdc++.h>
    2. using namespace std;
    3. #define int long long
    4. #define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    5. typedef pair<int,int> PII;
    6. const int N=2e6+10;
    7. vector <int> g[N];
    8. map <int,int> k;
    9. int p[N];
    10. int d[N];
    11. bool vis[N];
    12. vector <PII> q; //储存成环的边
    13. int n;
    14. void dfs(int u,int pa)
    15. {
    16. p[u]=pa;
    17. vis[u]=1;
    18. for (auto v:g[u])
    19. {
    20. if (v==pa) continue;
    21. if (vis[v]==1&&q.size()==0) //当点 v 被再次遍历时,现在已经建成一个环了,就可以回溯将环中的每条边放入队列 q 中
    22. {
    23. q.push_back({u,v});
    24. while (p[u]!=v)
    25. {
    26. q.push_back({u,p[u]});
    27. u=p[u];
    28. }
    29. q.push_back({u,p[u]});
    30. }
    31. if (vis[v]==1) continue; //走过的点,不用继续操作了,否则会死循环
    32. dfs(v,u);
    33. }
    34. }
    35. signed main()
    36. {
    37. ios;
    38. cin>>n;
    39. for (int i=1;i<=n;i++)
    40. {
    41. int u,v;
    42. cin>>u>>v;
    43. g[u].push_back(v);
    44. g[v].push_back(u);
    45. d[u]++;
    46. d[v]++;
    47. }
    48. for (int i=1;i<=n;i++)
    49. {
    50. k[d[i]]++; //记录度数相同的点的数量
    51. }
    52. //for (auto x:k) cout<<x.first<<" "<<x.second<<endl;
    53. dfs(1,0);
    54. //for (auto x:q) cout<<x.first<<" "<<x.second<<endl;
    55. int ans=0;
    56. for (auto x:q) //遍历每条要删掉的边
    57. {
    58. int du=d[x.first];
    59. int dv=d[x.second];
    60. k[du]--;
    61. k[dv]--;
    62. k[du-1]++;
    63. k[dv-1]++;
    64. int res=0;
    65. bool flag=0;
    66. for (auto y:k) //删除边后,再遍历每个点,判断能否成为根节点
    67. {
    68. int cnt=y.first;
    69. int s=y.second;
    70. if (cnt<=3) res +=s;
    71. if (cnt>=5&&s>0) flag=1; //既当不了根节点,也当不了儿子节点
    72. }
    73. if (flag==0) ans +=res;
    74. k[du]++; //还原
    75. k[dv]++;
    76. k[du-1]--;
    77. k[dv-1]--;
    78. }
    79. cout<<ans;
    80. return 0;
    81. }

  • 相关阅读:
    我的随记杂记
    连接器切断机维修
    Java_笔记_StringJoiner
    数字集成电路设计(五、仿真验证与 Testbench 编写)(三)
    elementui 实现树形控件单选
    如何在代码层面提高CPU分支预测效率
    leetCode 125. 验证回文串 + 双指针
    bpmn-js中实现xml数据转为json数据
    学编程始于C语言,但只学C远远不够的!
    SARScape使用GACOS数据
  • 原文地址:https://blog.csdn.net/m0_74403543/article/details/134515900