POJ 3352 Road Construction 中一个结论的证明

题面

分析:

很多人都给出了做法,在这里不赘述。大概就是先把桥找出来,然后边双缩点,最后统计新图上的度数。因为缩点后为一棵树,所以度数为1(即为叶子)的点的数目+1再除以2下取整就是答案。

这里主要证明一下为什么是对的。

表达式:\[答案=\lfloor\frac{叶子数+1}{2}\rfloor\]

证明:考虑一棵树中,我们找出带权重心,使得重心下每个子节点的叶子节点数尽量的平均(具体实现不讲了),那么在这棵尽量平均的树上,我们每次取两个根节点下子树不同的叶子节点连边,比如说最左边连最右边,左二连右二……,假如是偶数,那么搞定了。否则,那个点再随便连别的一棵子树的一个叶子(其实不是也行)就OK了。

觉得证明不严谨或者有问题的请指出,共同交流。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cctype>
using namespace std; 

const int maxn=1010;
int n,m,tot,head[maxn],cnt,dfn[maxn],low[maxn],c[maxn],ans,d[maxn];
bool br[maxn<<1],vis[maxn];
struct node
{
    int nxt,to;
}edge[maxn<<1];

int read()
{
    int x=0,f=1;
    char c=getchar();
    while (!isdigit(c))
        f=c=='-'?-1:1,c=getchar();
    while (isdigit(c))
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

void add(int u,int v)
{
    edge[++tot]=(node){head[u],v};
    head[u]=tot;
}

void tarjan(int u,int fa)   //get bridges
{
    int i,v;
    low[u]=dfn[u]=++cnt;
    for (i=head[u];i;i=edge[i].nxt)
    {
        v=edge[i].to;
        if (!dfn[v])
        {
            tarjan(v,i);
            low[u]=min(low[u],low[v]);
            if (low[v]>dfn[u])
                br[i]=br[i^1]=1;
        }
        else
        if (i!=(fa^1))
            low[u]=min(low[u],dfn[v]);
    }
}

void dfs(int u,int co)
{
    c[u]=co;
    int i,v;
    for (i=head[u];i;i=edge[i].nxt)
    {
        v=edge[i].to;
        if (br[i]||c[v])
            continue;
        dfs(v,co);
    }
}

int main()
{
    int i,j,u,v;
    n=read();
    m=read();
    tot=1;
    for (i=1;i<=m;i++)
    {
        u=read();
        v=read();
        add(u,v);
        add(v,u);
    }
    for (i=1;i<=n;i++)
        if (!dfn[i])
            tarjan(i,0);
    cnt=0;
    for (i=1;i<=n;i++)
        if (!c[i])
            dfs(i,++cnt);
    for (i=1;i<=n;i++)
        for (j=head[i];j;j=edge[j].nxt)
            if (c[i]!=c[edge[j].to])
            {
                d[c[i]]++;
                d[c[edge[j].to]]++;
            }
    for (i=1;i<=cnt;i++)
        if (d[i]==2)
            ans++;
    printf("%d\n",(ans+1)/2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Ronald-MOK1426/p/11776092.html