• JZOJ 6838. 【2020.10.31提高组模拟】小j的组合(树的直径)


    JZOJ 6838. 【2020.10.31提高组模拟】小j的组合

    题目大意

    • 给出一棵初始大小为 n n n的树,可以如下操作:
    • 选择一个选择一个点 v v v,再新增一个点 v ′ v' v,将 v ′ v' v连向所有与 v v v相连的点。
    • 求最少的操作次数及方案使得图中存在一条哈密顿回路。
    • n ≤ 100 nleq 100 n100

    题解

    • 哈密顿回路需要把每个点都经过一遍且只能经过一遍,除非是一条链,否则在树上都是不存在的。
    • 可以发现操作相当于把每个点复制一遍, 等同于给允许这个点多经过一次,有了这个结论就容易了许多。
    • 在树上DFS,每次返回到父亲就需要操作一次,但这样不能保证操作最少(当然,最后不需要回到根节点)
    • 不需要返回的点构成了一条链,剩下的每个点都需要返回操作一次,那么显然当这条链最长也就是直径的时候,操作次数最少,
    • 直接找出直径模拟即可。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 110
    int dis[N][N], p[N];
    int ans[N * 2], sum, n;
    void dfs(int k, int t) {
    	int x = 0;
    	ans[++ans[0]] = k, p[k] = 1;
    	for(int i = 1; i <= n; i++) if(dis[k][i] == 1 && !p[i]) {
    		if(dis[t][i] + 1 == dis[t][k]) {
    			x = i;
    			continue;
    		}
    		dfs(i, t);
    		printf("%d ", k);
    		ans[++ans[0]] = ++sum;
    	}
    	if(x) dfs(x, t);
    }
    int main() {
    	int i, j, k, x, y;
    	scanf("%d", &n);
    	for(i = 1; i <= n; i++)
    		for(j = 1; j <= n; j++) if(i == j) dis[i][j] = 0; else dis[i][j] = N;
    	for(i = 1; i < n; i++) {
    		scanf("%d%d", &x, &y);
    		dis[x][y] = dis[y][x] = 1;
    	}	
    	for(k = 1; k <= n; k++)
    		for(i = 1; i <= n; i++)
    			for(j = 1; j <= n; j++) dis[i][j] = min(dis[i][k] + dis[j][k], dis[i][j]);
    	int s = 1, t = 1;
    	for(i = 1; i <= n; i++)
    	 	for(j = 1; j <= n; j++) if(dis[i][j] > dis[s][t]) s = i, t = j;
    	printf("%d
    ", n - dis[s][t] - 1);
    	sum = n;
    	dfs(s, t);
    	printf("
    ");
    	for(i = 1; i <= ans[0]; i++) printf("%d ", ans[i]);
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    初拾Java(问题一:404错误,页面找不到)
    新年新气象--总结过去,展望未来
    接口测试[整理]
    [转]SVN-版本控制软件
    浅谈黑盒测试和白盒测试
    Bug管理工具的使用介绍(Bugger 2016)
    P2805/BZOJ1565 [NOI2009]植物大战僵尸
    近期学习目标
    P3643/BZOJ4584 [APIO2016]划艇
    P5344 【XR-1】逛森林
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910011.html
Copyright © 2020-2023  润新知