E. Railway System

题目:E. Railway System

考点:最小生成树kruskal、交互

题意:现有 n n n 个点 m m m 条边的无向图,一共可提出 2 m 2m 2m 次疑问,提问方式为每次输出一个长度为 m m m 由字符 1 / 0 1/0 1/0 组成的字符串 s s s s [ i ] = 0 s[i] = 0 s[i]=0 表示第 i i i 条边不存在, s [ i ] = 1 s[i] = 1 s[i]=1 表示第 i i i 条边存在。系统会给出由当前边所组成的最大森林(边权之和最大的森林),我们需要在 2 m 2m 2m 次提问中找出由所有边所构成的最小生森林((边权之和最大的森林))。

思路:题目是要求为求森林的值,在讨论的时候可以化繁为简,将最小森林变为最小树。以一个连通图为例
在这里插入图片描述
1.先利用 m m m 次的查询,获得每条边的权值 c n t i cnt_i cnti

2.我们可以发现最大生成树的权值为 2 + 4 + 8 + 5 = 19 2+4+8+5 = 19 2+4+8+5=19 ,在这里会发现一个现象,在成环的情况下会有不纳入计算中的边,同样由 k r u s k a l kruskal kruskal 算法可以得知,当某两点已经在同一个连通块中的时候,若还有关联这两点的边,则直接舍去。

3.创建一个集合 S S S 以及 r e s res res 记录当前集合所能构成的最小生成树的值,运用 k r u s k a l kruskal kruskal 的思想,将边权从小到大依次加入到集合 S S S 中,每次加入集合后,则进行一次询问,便会获得一个值 w i w_i wi ,如果 w i = c n t i + r e s w_i = cnt_i + res wi=cnti+res ,则表示当前边是构成最小生成树的边,然后 r e s = w i res = w_i res=wi。如果 w i ≠ c n t i + r e s w_i \not= cnt_i + res wi=cnti+res ,则表示当前边不是构成最小生成树的边,而且此时出现了环,所以需要将边 l i l_i li 从集合中去除。最后得到的 r e s res res 便是最小生成树的权值。

4.森林的做法与此相同。

#include<stdio.h>
#include<algorithm>

using namespace std;
const int N = 1e3 + 10;
char s[N];
int res;
struct node{
	int id,cnt;
}num[N];

bool cmp(node a1,node a2) {
	return a1.cnt < a2.cnt;
} 

int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	
	for(int i=0;i<m;i++) s[i] = '0';
	
	for(int i=0;i<m;i++) {
		s[i] = '1';
		printf("? %s\n",s);
		fflush(stdout);
		s[i] = '0';
		int k;
		scanf("%d",&k);
		num[i] = {i,k};
	} 
	
	sort(num,num+m,cmp);
	
	for(int i=0;i<m;i++) {
		s[num[i].id] = '1';
		printf("? %s\n",s);
		fflush(stdout);
		int k;
		scanf("%d",&k);
		if(k == res + num[i].cnt) res += num[i].cnt;
		else s[num[i].id] = '0';
	}
	
	printf("! %d\n",res);
	fflush(stdout);
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值