zoukankan      html  css  js  c++  java
  • BZOJ1912或洛谷3629 [APIO2010]巡逻

    一道树的直径

    BZOJ原题链接

    洛谷原题链接

    显然在原图上路线的总长为(2(n-1))
    添加第一条边时,显然会形成一个环,而这条环上的所有边全部只需要走一遍。所以为了使添加的边的贡献最大化,我们找出树的直径,将其两端点连上边即可。
    设直径长(L),于是路线总长就变为(2(n-1)-L+1=2n-L-1)
    (K=1)时,这就是答案。
    (K=2)时,我们考虑在上述添边后图中再添一条边。
    添加这条边同样会形成一个环,如果这个环与之前的环没有边重合的话,那么贡献和上一边一样,但如果有重边,就会导致重边又需要走两边。
    这就相当于添加的这条边在重边上的贡献为(-1),所以我们可以将第一次添边时搜到的直径上的所有边的权值改为(-1),然后依旧找出修改后的图的直径即可。
    设第一条直径长(L_1),第二条长(L_2),那么最终路线总长就变为(2(n-1)-L_1+1-L_2+1=2n-L_1-L_2)
    另外,注意因为第二次找直径时,有边的权值为负,这时普通的(dfs)找直径是无法找到正确的直径的。

    #include<cstdio>
    using namespace std;
    const int N = 1e5 + 10;
    int di[N << 1], da[N << 1], ne[N << 1], fi[N], dis[N], D[N], dia, l;
    inline int re()
    {
    	int x = 0;
    	char c = getchar();
    	bool p = 0;
    	for (; c<'0' || c>'9'; c = getchar())
    		p |= c == '-';
    	for (; c >= '0'&&c <= '9'; c = getchar())
    		x = x * 10 + (c - '0');
    	return p ? -x : x;
    }
    inline void add(int x, int y)
    {
    	di[++l] = y;
    	da[l] = 1;
    	ne[l] = fi[x];
    	fi[x] = l;
    }
    inline int maxn(int x, int y)
    {
    	return x > y ? x : y;
    }
    void dfs(int x, int fa, int d)
    {
    	int i, y;
    	if (dia < d)
    	{
    		dia = d;
    		D[0] = x;
    	}
    	D[x] = fa;
    	for (i = fi[x]; i; i = ne[i])
    	{
    		y = di[i];
    		if (y != fa)
    			dfs(y, x, d + 1);
    	}
    }
    void fixda(int x, int y)
    {
    	int i;
    	for (i = fi[x]; i; i = ne[i])
    		if (di[i] == y)
    		{
    			da[i] = -1;
    			return;
    		}
    }
    void dp(int x, int fa)
    {
    	int i, y;
    	for (i = fi[x]; i; i = ne[i])
    	{
    		y = di[i];
    		if (y != fa)
    		{
    			dp(y, x);
    			dis[0] = maxn(dis[0], dis[x] + dis[y] + da[i]);
    			dis[x] = maxn(dis[x], dis[y] + da[i]);
    		}
    	}
    }
    int main()
    {
    	int i, n, m, x, y;
    	n = re();
    	m = re();
    	for (i = 1; i < n; i++)
    	{
    		x = re();
    		y = re();
    		add(x, y);
    		add(y, x);
    	}
    	dfs(1, 0, 0);
    	dia = 0;
    	dfs(D[0], 0, 0);
    	if (m == 1)
    	{
    		printf("%d", (n << 1) - dia - 1);
    		return 0;
    	}
    	for (x = D[0]; x; x = y)
    	{
    		y = D[x];
    		fixda(x, y);
    		fixda(y, x);
    	}
    	dp(1, 0);
    	printf("%d", (n << 1) - dia - dis[0]);
    	return 0;
    }
    
  • 相关阅读:
    Java回调函数的理解
    android 解析json数据格式
    python类型转换、数值操作(收藏)
    PyQt4学习资料汇总 (转)
    HDU 2767 Proving Equivalences (Tarjan )
    apache2的安装与简单配置(转)
    HDU 3861 The King’s Problem (Tarjan + 二分匹配)
    MySql的一些基本使用及操作命令 (待更新)
    pcap的安装与配置
    ubuntu下配置安装PYQT4
  • 原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9574268.html
Copyright © 2011-2022 走看看