7-14保持安全社交距离的重要性 最小生成树板子题

在新冠疫情期间保持社交距离非常有必要,疾控专家普遍认为保持1米以上的距离可以有效减缓疫情传播。现在给定一些人的坐标,请你计算一下他们是否都安全,如果不安全,那么新冠病毒最快多久能感染所有人。为了方便计算,我们使用厘米作为距离单位,达到或者超过100厘米,我们就认为两个人之间是安全的,如果距离D小于100厘米,那么我们设定病毒会花D秒从一个人传到另一个人。
输入格式:

首先输入人的个数N,随后N行,依次输入N个人的坐标。
输出格式:

对每一组输入,如果所有人之间都能保持安全距离,输出“Good! All are safe!”,如果只有1个人能保持安全距离,输出“Only 1 person is safe!”,如果有2个或者2个以上的人能保持安全距离,但是并不是所有人都保持安全距离,输出“K persons are safe!”,K是人数,如果所有人都不能保持安全距离,那么输出“Warning! All persons are in Danger! Virus will infect everyone in X seconds!”,X是病毒感染所有人所花的最短时间,精确到小数点后2位。
输入样例:

在这里给出一组输入。例如:

2
0 0
1 1

输出样例:

在这里给出相应的输出。例如:

Warning! All persons are in Danger! Virus will infect everyone in 1.41 seconds!

作者
胡伟平
单位
广西科技大学
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

作者
胡伟平
单位
广西科技大学
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB


预习考试大半个月终于解放回来写题了,
这是我们校赛的一道题,当时比赛的时候瞄了一眼觉得是简单的板子题就没做,


思路:

  • 二维平面有一堆散点,要求出最小生成树后,断开所有边权大于等于100的边,于是树可能变成多个不连通的图,然后照着题目意思打印就行了.
  • 实际上,我们不需要实现断边操作,因为如果图不连通kruscal算法可以直接生成多个不连通的最小生成树,
  • 但是二维平面点的最小生成树如果要使用kruscal必须加三角剖分(我不会)才能得到比较优秀的复杂度,
    由于老师不想卡我们,所以本题直接瞎搞就行了
#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN ((int)3e6+7)
#define ll long long 
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...)                             \
    do {                                       \
        cout << "\033[31;1m " << #x << " -> "; \
        err(x);                                \
    } while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO {

	char print_f[105];
	void read() { }
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
		inline void read(T &x, T2 &... oth) {
			x = 0;
			char ch = getchar();
			ll f = 1;
			while (!isdigit(ch)) {
				if (ch == '-') f *= -1; 
				ch = getchar();
			}
			while (isdigit(ch)) {
				x = x * 10 + ch - 48;
				ch = getchar();
			}
			x *= f;
			read(oth...);
		}
	template <typename T, typename... T2>
		inline void print(T x, T2... oth) {
			ll p3=-1;
			if(x<0) putchar('-'), x=-x;
			do{
				print_f[++p3] = x%10 + 48;
			} while(x/=10);
			while(p3>=0) putchar(print_f[p3--]);
			putchar(' ');
			print(oth...);
		}
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K;

#define fst first 
#define sec second

vector<pair<int,int> > vec;

struct Edge {
	int u, v;
   	double dst;
	bool operator < (const Edge& ed) const {
		return dst< ed.dst;
	}
} edge[MAXN];

inline double getdist(double x1, double y1, double x2, double y2) {
	double X = x1 - x2, Y = y1 - y2;
	return sqrt(X*X + Y*Y);
}

int pre[MAXN], pre2[MAXN], cnt[MAXN];
double ptime[MAXN];

void init() {
	for(int i=0; i<=n; i++) pre[i] = pre2[i] = i, cnt[i] = 1;
}

int fa(int* ptr, int x) {
	return x==ptr[x] ? x : (ptr[x]=fa(ptr, ptr[x]));
}

void union_xy(int* ptr, int x, int y) {
	x = fa(ptr, x), y = fa(ptr, y);
	if(x != y) 
		cnt[x] += cnt[y], ptr[y] = ptr[x];
}

#define double_inf (1e18)
void krs() {
	init();
	sort(edge+1, edge+1+m);
	int k = int(vec.size()) - 1;
	double tmin = double_inf, sum = 0;
	for(int i=1; i<=m && k; i++) {
		int u = edge[i].u, v = edge[i].v;
		double w = edge[i].dst;

		//这里加入判断边权长度即可跳过不符合的边
		if(fa(pre, u) == fa(pre, v) || w >= 100.) continue ;
		
		k --;
		union_xy(pre, u, v);
		sum += w;
	}
	int root = 0/*根节点个数*/, ans = 0/*落单点个数*/;
	for(int i=0; i<n; i++) {
		if(pre[i] == i) {
			root ++;
			if(cnt[i] == 1) {
				ans ++;
			}
		}
	}
	if(root == 1) { //只有一个根,说明所有点都被联通了
		printf("Warning! All persons are in Danger! Virus will infect everyone in %.2lf seconds!", sum);
	} else if(root == 2 && ans == 1) { //只有两个联通块,其中一个是单点
		printf("Only 1 person is safe!\n");
	} else if(root == n) { //n个联通块
		printf("Good! All are safe!\n");
	} else { //小于n个联通块
		printf("%d persons are safe!", ans);
	}
}

int main() {
#ifdef debug
	freopen("test", "r", stdin);
	// freopen("out_main", "w", stdout);
	clock_t stime = clock();
#endif
	read(n);
	pair<int, int> p;
	for(int i=0; i<n; i++) {
		read(p.fst, p.sec);
		for(int k=0; k<int(vec.size()); k++) {
			edge[++m].u = i, edge[m].v = k;
			edge[m].dst = getdist(vec[k].fst, vec[k].sec, p.fst, p.sec);
		}
		vec.push_back(p);
	}
	krs();




#ifdef debug
	clock_t etime = clock();
	printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
	return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值