zoukankan      html  css  js  c++  java
  • UVA10972 RevolC FaeLoN

    题目链接:vjudge

    大意:给出一个无向图,你需要给这个无向图中的所有边定向,并且再添加尽量少的有向边,使得新得到的图强连通

    先考虑这样一个问题:什么样的无向图可以经过重定向得到一个强连通图

    考察一下强连通图的定义:(forall u,v(u eq v)),同时存在(u->v)(v->u)的路径,注意到这样的两条路径显然是不可能有重边的,这样的话把这个定义转换到无向图上就变成了:(forall u,v(u eq v)),存在两条(u->v)的路径,且路径上无重边

    等等,这不就是边双连通分量的定义吗

    所以我们得到了一个结论:一个无向图可以经过重定向得到一个强连图当且仅当这个无向图是一个边双连通分量

    那么我们先将这个图的每一个边双连通分量缩成一个点,这样我们最后就得到了一棵树,我们需要加尽量少的边使这棵树变成一个边双连通分量

    等等,这不就是这道题吗,最后的结论就是你可以两两叶子之间连一下,最后使得所有点度数均大于1即可,构造方案如下:这棵树先表示成叶节点在最下面的形式,然后连接最近公共祖先最浅的两个点u,v,记其公共祖先为p,如此一来相当于u到p和v到p上所有路径都缩在p上,路径上往下连的子树也缩在p上。其他点对的公共祖先都比p深,因此新的最浅的最近公共祖先p’不会比p更深。再重复上述操作,直到p为叶节点。

    这道题做完了?并没有,原题给出的图可能不是连通图

    我们发现不是联通的情况下出现影响的只可能是“孤点”(即那些不与任何点连边的点),你可以先将它和某个叶子连一条边,这样在产生一个叶子的同时又消去了一个叶子

    最后的答案就是:孤点个数+(frac{缩点后叶子个数+1}{2})

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<math.h>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    const int N=10000;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define fir first
    #define sec second
    #define mp(a,b) make_pair(a,b)
    #define pb(a) push_back(a)
    #define maxd 998244353
    #define eps 1e-8
    int n,m,dfn[1010],low[1010],d[1010],mark[1010],tot=0,tim=0;
    vector<int> sq[1010];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    void tarjan(int u,int fa)
    {
    	dfn[u]=low[u]=(++tim);
    	int len=sq[u].size();
    	rep(i,0,len-1)
    	{
    		int v=sq[u][i];
    		if (v==fa) continue;
    		if (!dfn[v])
    		{
    			tarjan(v,u);
    			low[u]=min(low[u],low[v]);
    			if (low[v]>dfn[u]) tot++;
    		}
    		else low[u]=min(low[u],dfn[v]);
    	}
    }
    
    int main()
    {
    	//freopen("a.out","w",stdout);
    	while (scanf("%d%d",&n,&m)==2)
    	{
    		rep(i,1,n) sq[i].clear();
    		rep(i,1,m)
    		{
    			int u=read(),v=read();
    			sq[u].pb(v);sq[v].pb(u);
    		}
    		memset(dfn,0,sizeof(dfn));
    		memset(low,0,sizeof(low));
    		tot=0,tim=0;
    		rep(i,1,n)
    			if (!dfn[i])
    			{
    				tot++;tarjan(i,0);
    			}
    		if (tot==1) {puts("0");continue;}
    		memset(mark,0,sizeof(mark));
    		memset(d,0,sizeof(d));
    		rep(i,1,n) mark[low[i]]=1;
    		rep(u,1,n)
    		{
    			int len=sq[u].size();
    			rep(i,0,len-1)
    			{
    				int v=sq[u][i];
    				if (low[u]!=low[v]) d[low[u]]++;
    			}
    		}
    		int ans0=0,ans1=0;
    		rep(i,1,n)
    		{
    			if (mark[i])
    			{
    				if (!d[i]) ans0++;
    				else if (d[i]==1) ans1++;
    			}
    		}
    		printf("%d
    ",ans0+(ans1+1)/2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    火柴排队sol
    国王游戏sol
    子串sol
    跳石头
    解方程sol
    花匠sol
    字符串整理
    计算系数
    矩阵取数游戏sol
    8.2_java_28
  • 原文地址:https://www.cnblogs.com/encodetalker/p/11306364.html
Copyright © 2011-2022 走看看