L3-005 垃圾箱分布 (最短路)

本文介绍了一种用于确定垃圾箱在居民区中最佳位置的算法。该算法考虑了居民点到垃圾箱的距离,确保每个居民点都在一个合理的范围内,并且垃圾箱不会过于靠近任何一个居民点。通过运行多次Dijkstra算法,找到满足条件的最适地点。

大家倒垃圾的时候,都希望垃圾箱距离自己比较近,但是谁都不愿意守着垃圾箱住。所以垃圾箱的位置必须选在到所有居民点的最短距离最长的地方,同时还要保证每个居民点都在距离它一个不太远的范围内。

现给定一个居民区的地图,以及若干垃圾箱的候选地点,请你推荐最合适的地点。如果解不唯一,则输出到所有居民点的平均距离最短的那个解。如果这样的解还是不唯一,则输出编号最小的地点。

输入格式:

输入第一行给出4个正整数:N(≤10​3​​)是居民点的个数;M(≤10)是垃圾箱候选地点的个数;K(≤10​4​​)是居民点和垃圾箱候选地点之间的道路的条数;D​S​​是居民点与垃圾箱之间不能超过的最大距离。所有的居民点从1到N编号,所有的垃圾箱候选地点从G1到GM编号。

随后K行,每行按下列格式描述一条道路:

P1 P2 Dist

其中P1P2是道路两端点的编号,端点可以是居民点,也可以是垃圾箱候选点。Dist是道路的长度,是一个正整数。

输出格式:

首先在第一行输出最佳候选地点的编号。然后在第二行输出该地点到所有居民点的最小距离和平均距离。数字间以空格分隔,保留小数点后1位。如果解不存在,则输出No Solution

输入样例1:

4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2

输出样例1:

G1
2.0 3.3

输入样例2:

2 1 2 10
1 G1 9
2 G1 20

输出样例2:

No Solution

解题思路

 跑m遍dijkstra求各个候选地点到所有居民点的最短距离,记录最短距离里的最大距离x和平均距离av。然后选择x最大的候选地点。如果存在多个,则选择av最小的,还存在多个,则选择编号小的。没有就输出No Solution。

代码如下

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#define maxn 1020
#define INF 0x3f3f3f3f
using namespace std;
int g[maxn][maxn];
int dis[15][maxn];
bool vis[maxn];
int s[15];
double av[15];
int main()
{
	int n, m, k, dist;
	cin >> n >> m >> k >> dist;
	for(int i = 1; i <= n + m; i ++){
		for(int j = 1; j <= n + m; j ++)
			g[i][j] = INF;
		g[i][i] = 0;
	} 
	for(int i = 0; i < k; i ++){
		string str1, str2;
		int d;
		cin >> str1 >> str2 >> d;
		int x, y;
		x = y = 0;
		if(str1[0] == 'G'){
			for(int i = 1; i < str1.size(); i ++)
				x = x * 10 + str1[i] - '0';
			x += n;
		}
		else {
			for(int i = 0; i < str1.size(); i ++)
				x = x * 10 + str1[i] - '0';
		}
		if(str2[0] == 'G'){
			for(int i = 1; i < str2.size(); i ++)
				y = y * 10 + str2[i] - '0';
			y += n;
		}
		else {
			for(int i = 0; i < str2.size(); i ++)
				y = y * 10 + str2[i] - '0';
		}
		g[x][y] = g[y][x] = d;
	}
	for(int i = 1; i <= m; i ++){
		for(int j = 1; j <= n + m; j ++){
			dis[i][j] = g[n + i][j];
		}
	}
	for(int i = 1; i <= m; i ++){
		memset(vis, 0, sizeof(vis));
		vis[n + i] = true;
		for(int j = 1; j < n + m; j ++){
			int minn = INF;
			int k = 0;
			for(int v = 1; v <= n + m; v ++){
				if(!vis[v] && dis[i][v] < minn){
					minn = dis[i][v];
					k = v;
				}
			}
			vis[k] = true;
			for(int v = 1; v <= n + m; v ++){
				if(!vis[v] && g[k][v] != INF && dis[i][v] > dis[i][k] + g[k][v])
					dis[i][v] = dis[i][k] + g[k][v];
			}
		}
	}
	bool flg[15] = {0};
	for(int i = 1; i <= m; i ++){
		s[i] = INF;
		for(int j = 1; j <= n; j ++){
			if(dis[i][j] < s[i])
				s[i] = dis[i][j];
			av[i] += (double)dis[i][j];
			if(dis[i][j] > dist)
				flg[i] = true;
		}
		av[i] /= (double)n;
	}
	int ans = 0;
	int maxx = -1;
	double ta = INF;
	for(int i = 1; i <= m; i ++){
		if(!flg[i]){
			if(s[i] > maxx || s[i] == maxx && av[i] < ta){
				maxx = s[i];
				ans = i;
				ta = av[i];
			}
		}
	}
	if(maxx == -1)
		cout << "No Solution" << endl;
	else {
		cout << "G" << ans << endl;
		printf("%.1lf %.1lf\n", (double)maxx, ta);
	} 
	return 0;	
}

 

### l3-005 垃圾箱分布 Java 实现方案 对于垃圾箱分布问题,在Java实现中,可以考虑使用数据结构来模拟城市中的不同位置以及这些位置上的垃圾量。通过遍历和计算找到优解。 #### 使用二维数组表示地图 为了简化模型,假设有一个n*m大小的城市网格图,其中每个格子代表一个区域,区域内有特定数量的垃圾需要处理。可以通过如下方式定义: ```java int[][] cityMap = { {1, 2, 3}, {4, 8, 2}, {1, 7, 9} }; ``` 这里`cityMap[i][j]`表示第i行第j列的位置上有多少单位垃圾待清理[^1]。 #### 定义垃圾桶放置策略 考虑到实际应用中可能存在的多种约束条件(比如成本小化),下面给出一种简单的贪心算法思路:总是尝试把新的垃圾桶放在当前未覆盖到的大值处直到满足一定比例或总数的要求为止。 ```java public class GarbageBinDistribution { private static final int MAX_BINS = 5; public static void placeBins(int[][] map){ PriorityQueue<int[]> maxHeap = new PriorityQueue<>((a,b)->b[2]-a[2]); for (int i=0;i<map.length;i++){ for (int j=0;j<map[0].length;j++){ if(map[i][j]>0){ maxHeap.offer(new int[]{i,j,map[i][j]}); } } } while (!maxHeap.isEmpty() && placedBinsCount < MAX_BINS){ int[] topEntry = maxHeap.poll(); System.out.printf("Placing bin at (%d,%d)\n",topEntry[0],topEntry[1]); // 这里还可以加入更多逻辑,例如更新周围节点的状态等... placedBinsCount++; } } private static int placedBinsCount; } ``` 此代码片段展示了如何利用优先级队列(PriorityQueue)来高效地选取具有垃圾量的地方设置垃圾桶,并打印出所选地点的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值