见面礼——图论

给定一个 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条边,所以该图就成一个环。只有将环中的一条边删去,该图才能变为一棵树。

复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long 
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef pair<int,int> PII;
const int N=2e6+10;
vector <int> g[N];
map <int,int> k;
int p[N];
int d[N];
bool vis[N];
vector <PII> q;  //储存成环的边
int n;
void dfs(int u,int pa)
{
    p[u]=pa;
    vis[u]=1;
    for (auto v:g[u])
    {
        if (v==pa) continue;
        if (vis[v]==1&&q.size()==0)    //当点 v 被再次遍历时,现在已经建成一个环了,就可以回溯将环中的每条边放入队列 q 中
        {
            q.push_back({u,v});
            while (p[u]!=v)
            {
                q.push_back({u,p[u]});
                u=p[u];
            }
            q.push_back({u,p[u]});
        }
        if (vis[v]==1) continue;  //走过的点,不用继续操作了,否则会死循环
        dfs(v,u);
    }
}
signed main()
{
    ios;
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
        d[u]++;
        d[v]++;
    }
    for (int i=1;i<=n;i++)
    {
        k[d[i]]++;  //记录度数相同的点的数量
    }
    //for (auto x:k) cout<<x.first<<" "<<x.second<<endl;
    dfs(1,0);
    //for (auto x:q) cout<<x.first<<" "<<x.second<<endl;
    int ans=0;
    for (auto x:q)   //遍历每条要删掉的边
    {
        int du=d[x.first];
        int dv=d[x.second];
        k[du]--;
        k[dv]--;
        k[du-1]++;
        k[dv-1]++;
        int res=0;
        bool flag=0;
        for (auto y:k)       //删除边后,再遍历每个点,判断能否成为根节点
        {
            int cnt=y.first;
            int s=y.second;
            if (cnt<=3) res +=s;
            if (cnt>=5&&s>0) flag=1;    //既当不了根节点,也当不了儿子节点
        }
        if (flag==0) ans +=res;
        k[du]++;  //还原
        k[dv]++;
        k[du-1]--;
        k[dv-1]--;
    }
    cout<<ans;
    return 0;
}
相关推荐
如果你想拥有什么先让自己配得上拥有9 小时前
数、自然数、整数、有理数、无理数它们的定义由来和边界划分
算法
Xの哲學10 小时前
Linux SLUB 内存分配器深度剖析: 从设计哲学到实战调试
linux·服务器·网络·算法·边缘计算
tobias.b10 小时前
408真题解析-2009-1-数据结构-队列-进出规则-应用
数据结构·考研·408真题
2401_8762213410 小时前
AtCoder Beginner Contest 439 - D - Kadomatsu Subsequence
c++·算法
小丁努力不焦虑10 小时前
算法期末总结题
数据结构·算法
嵌入式进阶行者10 小时前
【算法】从数组中选取两个符合一定条件的数的算法与实例:华为OD机考双机位A卷 - 跳房子I
数据结构·c++·算法·链表
老歌老听老掉牙10 小时前
从战场到商场:最优化算法如何用数学重塑世界?
python·算法·最优化
im_AMBER10 小时前
Leetcode 94 合并零之间的节点
数据结构·c++·笔记·学习·算法·leetcode
tobias.b10 小时前
408真题解析-2009-3-数据结构-树-遍历方式
数据结构·计算机考研·408真题
KingRumn10 小时前
DBUS源码剖析之DBusMessage消息头
linux·服务器·算法