#801 Div.2 D. Tree Queries 结论

1695D
结论题,大佬们画画图就出来了,蒻想了1h也没想出来。又画了一会图,懂了但也不会详细证明。

题意

现在有一棵 n n n 个节点的树(边权均为1),和一个未知的点 x ( 1 ≤ x ≤ n ) x(1\leq x\leq n) x(1xn),你可以询问 k k k 个点,并在所有问题问完后分别得知这 k k k 个点与 x x x 的最短路径长度。你的目的是找到最小的 k k k,使得对于任意的 x x x,你都可以确定 x x x 的位置。
(题目中 x x x 的数量是不定的,但当成1个就可)

思路

首先询问的一定都是叶节点(询问叶节点的父亲节点,一定不优于询问叶节点,其他点同理),如果把所有叶节点都询问了,肯定是可以的,但当然不需要全选,考虑怎么删去。画了一会图,感觉只和分叉有关,链的长度不管是1还是多少都不会影响。
方法就是从每个叶节点开始遍历直到遇到度超过2的点(即分叉),如果它没有被访问过则这个叶节点可以删去。
在这里插入图片描述
比如这样一个图,分叉在1和2,那么对应的7和5可以删去一个,4和8可以删去一个。

代码

vector<int> e[maxn];
int vis[maxn];
void solve() {
    int n;
    cin >> n;
    if(n == 1) {
    	cout << 0 << endl;
    	return;
    }
    for(int i = 1; i <= n; i++) {
    	e[i].clear();
    	vis[i] = 0;
    }
    bool flag = 1;
    for(int i = 1; i < n; i++) {
    	int x, y;
    	cin >> x >> y;
    	e[x].pb(y);
    	e[y].pb(x);
    	if(e[x].size() > 2 || e[y].size() > 2) flag = 0;
    }
    if(flag) {
    	cout << 1 << endl;
    	return;
    }
    int ans = 0;
    for(int i = 1; i <= n; i++) {
    	if(e[i].size() == 1) {
    		ans++;
    		int j = e[i][0], k = i;
    		while(e[j].size() <= 2) {
    			k ^= e[j][0] ^ e[j][1];
    			swap(j, k);
    		}
    		if(!vis[j]) {
    			vis[j] = 1;
    			ans--;
    		}
    	}
    }
    cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值