LA 3708 - Graveyard

本文介绍了一种算法,用于解决在固定长度直线上调整多个雕像位置的问题。通过将直线分割并利用映射记录每个位置的状态,确保雕像之间的最优分布,同时最小化移动距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说一下自己的思路吧,我的方法虽然通过了,但是比较直接,没有具备太多的技巧性。首先将长度为10000的直线分成为n份,计算出每一份的长度dis1,然后依次处理每一个位置上的雕像。处理过程如下:将长度为10000的直线分成n+m份,对于每一个已经放置在直线的雕像的位置,开始判断后面的划分方法中是否划分的点和这个雕像的位置是重合的,并且没有放置其他的雕像,注意这里对于直线上的位置是否放置了雕像我们使用了一个map映射来记录的。如果位置恰好是重合的,那么说明该雕像的位置是不需要移动的,同时要记得更改对应的map的值。如果当前判断的位置恰好在这个雕像位置之前并且下一个待判断的位置恰好在当前的雕像的位置之后,那么就讨论这两个位置是否已经放置了雕像,如果恰好两个位置都没有放置雕像,那么就选择最近的一个位置放置对应的雕像,否则如果两个位置中有一个位置是没有放置雕像的,那么就将当前的雕像移动到对应的位置,最后处理最极端的一种情况,如果碰巧两个位置都放置了雕像,那么就向前查找第一个可以放置待移动雕像的地方,同时向后查找第一个可以放置雕像的地方,然后按照位置的远近进行取舍,并且更新map。注意每次在移动了雕像之后要将移动的值记录到最终的结果res中,最后输出,保留四位小数就可以了,具体实现见如下代码:

#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<unordered_map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
#include<utility>
using namespace std;

int n, m;

int main(){
	while (cin >> n >> m){
		double res = 0;
		map<double, bool> record;
		double dis1 = 10000.0 / n;
		double dis2 = 10000.0 / (n + m);
		for (double loc = 0; loc < 10000.0; loc += dis1){
			for (double loc1 = 0; loc1 < 10000.0; loc1 += dis2){
				if (loc1 == loc&&record.find(loc1) == record.end()){
					record[loc1] = true;
					break;
				}
				if (loc1<loc&&loc1 + dis2>loc){//正好在二者之间
					double st = loc1, ed = loc1 + dis2;
					if (record.find(st) == record.end() 
						&& record.find(ed) == record.end()){
						double res_t = min(abs(loc - st), abs(ed - loc));
						res += res_t;
						if (st + res_t == loc) record[st] = true;
						else if (loc + res_t == ed) record[ed] = true;
					}
					else if (record.find(st)==record.end()){
						res += (loc - st);
						record[st] = true;
					}
					else if (record.find(ed)==record.end()){
						res += (ed - loc);
						record[ed] = true;
					}
					else{
						while (st >= 0 && record[st] != true){
							st -= dis2;
						}
						while (ed < 10000.0&&record[ed] != true){
							ed += dis2;
						}
						if (st >= 0 && ed < 10000.0){
							double res_t = min(abs(loc - st), abs(ed - loc));
							res += res_t;
							if (st + res_t == loc) record[st] = true;
							else if (loc + res_t == ed) record[ed] = true;
						}
						else if (st>=0){
							res += (loc - st);
							record[st] = true;
						}
						else{
							res += (ed - loc);
							record[ed] = true;
						}
					}
				}
			}
		}
		cout <<fixed<<setprecision(4)<< res << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值