L3-005 垃圾箱分布 (30 分)

题目

题目链接

题解

对每个垃圾箱进行一次队列优化的Dijskra,每算出一个垃圾箱到其余各个居民点的最短距离后,计算这些距离中的最大距离、最短距离。如果最大距离大于要求的距离则直接忽略这个位置放垃圾桶的情况;否则,如果最短距离小于已经记录的最大的最短距离或者最短距离等于已经记录的最大的最短距离并且距离均值小于已经记录的最小均值,则更新要输出的信息。

优先级:

  1. 最短距离要最大
  2. 距离均值要最小
  3. 垃圾桶编号要小(由于我们是顺序判断每种情况,所以不需要通过该条件进行更新)

注意:

直接printf("%.1lf")输出均值是过不了样例的,但是可以AC。

通过printf进行四舍五入会存在一些问题,这也是我在输出样例的时候发现的。

printf四舍五入问题

所以最好还是通过+0.5来处理

代码

#include<bits/stdc++.h>
#define PII pair <int, int>
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 5e4 + 10;

int n, m, k, MAXDIST;
int best_pos, best_mindist = INF;
int maxmindist = -1; // 最大的最短距离 
int d[N];
int w[N], e[N], ne[N], h[N], idx;
double best_sum;

void add (int a, int b, int c) {
	w[idx] = c, e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

void Dijkstra (int x) { // Dijkstra优先队列优化模板 
	
	memset (d, 0x3f, sizeof d);
	d[x] = 0;
	
	priority_queue <PII, vector <PII>, greater<PII> > q;
	q.push ({0, x});
	
	while (q.size()) {
		PII tt = q.top ();
		q.pop ();
		int t = tt.second;
		int dist = tt.first;
		
		if (dist != d[t]) continue;
		
		for (int i = h[t];~i;i = ne[i]) {
			int j = e[i];
			if (d[j] > d[t] + w[i]) {
				d[j] = d[t] + w[i];
				q.push ({d[j], j});
			}
		}
	}	
}

int main()
{
	memset (h, -1, sizeof h);
	cin >> n >> m >> k >> MAXDIST;
	while (k --) {
		string a, b;
		int c;
		cin >> a >> b >> c;
		int aa, bb;
		if (a[0] == 'G') aa = atoi (a.substr(1).c_str()) + n; // 如果是垃圾箱就让编号从n+1开始 
		else aa = atoi (a.c_str());
		if (b[0] == 'G') bb = atoi (b.substr(1).c_str()) + n;
		else bb = atoi (b.c_str());
		add (aa, bb, c);
		add (bb, aa, c);
	}	
	
	for (int i = n+1;i <= n+m;i ++) {
		double sum = 0.0;
		int maxdist = -1, mindist = INF;
		Dijkstra (i);
// 		cout << "such as : ";
		for (int j = 1;j <= n;j ++) {
			sum += 1.0 * d[j];
			maxdist = max (maxdist, d[j]); // 以第i-n号垃圾桶为起点到其他各个居民的距离的最大值 
			mindist = min (mindist, d[j]); // 以第i-n号垃圾桶为起点到其他各个居民的距离的最小值 
// 			cout << d[j] <<  ' ';
		}
// 		cout << endl;
		// 最大距离必须小于要求  判断最小距离是否大于最大最短距离(若大于则更新)或者最小距离等于最大的最短距离,比较均值,也就是比较分子(距离和) 
		if (maxdist <= MAXDIST && (mindist > maxmindist || (mindist == maxmindist && sum < best_sum))) {
			// 保存最佳输出答案 
			best_pos = i;
			best_sum = sum;
			best_mindist = mindist;
			// 更新用于更新最佳输出答案的数据 
			maxmindist = mindist;
		}
	}
	if (!best_pos) puts ("No Solution");
	else printf ("G%d\n%.1lf %.1lf", best_pos-n, 1.0 * best_mindist, (int(best_sum / n * 10 + 0.5)) / 10.0);
	// 这个输出真离谱,如果直接 printf("%.1lf", best_sum / n) 样例都过不了却能AC

	return 0;
}

沃日,好离谱,之前写了个大根堆都尼玛能AC!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不牌不改

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值