zoukankan      html  css  js  c++  java
  • POJ 3352 Road Construction 中一个结论的证明

    题面

    分析:

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

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

    表达式:$$答案=lfloorfrac{叶子数+1}{2} floor$$

    证明:考虑一棵树中,我们找出带权重心,使得重心下每个子节点的叶子节点数尽量的平均(具体实现不讲了),那么在这棵尽量平均的树上,我们每次取两个根节点下子树不同的叶子节点连边,比如说最左边连最右边,左二连右二……,假如是偶数,那么搞定了。否则,那个点再随便连别的一棵子树的一个叶子(其实不是也行)就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
    ",(ans+1)/2);
    	return 0;
    }
    
  • 相关阅读:
    2013上半年学习目录
    《linux c编程指南》学习手记4
    Oracle二三事之 Oracle SPARC SuperCluster的九大技术优势
    《linux c编程指南》学习手记5
    Oracle二三事之 数据迁移注意事项
    《linux c编程指南》学习手记3
    在IIS中实现JSP
    为什么匿名内部类参数必须为final类型
    sql server和mysql变量赋值的区别 以及 MySql Declare
    android上传文件到服务器
  • 原文地址:https://www.cnblogs.com/Ronald-MOK1426/p/11776092.html
Copyright © 2011-2022 走看看