CSU1568-Shrine Maintenance

本文探讨了在一个半径为1000单位的圆上,根据特定规则放置神社,并利用算法来确定工人进行维护时的最短路径,旨在减少神社关闭时间。

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

Shrine Maintenance

            Time Limit: 2 Sec       Memory Limit: 128 Mb       Submitted: 140       Solved: 68       SpecialJudge

Description

A religious sect has holy sites with shrines placed around a circle of radius 1000. The circle is split into N equal length arcs and the endpoints are numbered in order, 1 through N. The first figure shows a circle where N is 12, with 12 gray tick marks like on a 12-hour analog clock. We can imagine the marks numbered, as on a clock, with 12 at the top. Each circle has one or more sacred numbers associated with it. The sacred numbers for the circle in the first figure are 2 and 3. A shrine, indicated by a black dot in the figure, is placed at each mark whose number is a multiple of at least one of the sacred numbers, so in this case the shrines are at positions 2, 3, 4, 6, 8, 9, 10, and 12.


When it comes time to inspect and repair the shrines at a given site, the area is closed and a team of workers simultaneously fan out from a maintenance shed, located in the center of the circle, so that each shrine is visited by at least one worker. Once all workers have returned to the shed, the site is reopened to the public. Because these sites are in great demand, it is important that they be closed as briefly as possible. In order to minimize this time, they must figure out how to apportion the shrines among the current number of workers, so the maximum distance traveled by any one worker is as small as possible. Figure 1 shows one choice for the optimal solution paths for 3 workers. The lower left path has darker lines, to indicate that it is one with the longest length, which in this case is approximately 3517.6. 
This sect has many circular sites with multiple shrines. The number of available workers at a site, W, the value of the number equal arcs, N, and the sacred numbers vary between sites. The sacred numbers are always divisors of N. Your job is to help figure out how much time is required for maintenance. Figures 2 and 3 show optimal solutions for other sites.

Input

The input consists of one or more data sets. Each data set is on a single line and consists entirely of positive integers. The first three entries are W, the number of workers, N, the number of equal arcs around the circle, and D, the number of sacred divisors of N. At the end come the D divisors of N. W is no more than the total number of shrines; N ≤ 8600, and D ≤ 6; each listed divisor of N is smaller than N.

A single zero, 0, will be placed on the last line to indicate the end of the input.

Output

The output is a single line for each dataset: the maximum distance a worker must travel with an optimal assignment of the shrines. This number is displayed so that it is rounded to one decimal place, and always shows that decimal place, even if it is 0. To ensure unique answers with double arithmetic, the datasets are chosen so that if your answer is anywhere within .005 of the exact minimum distance, then the answer rounded to one decimal place will be the same.

The first three sample datasets correspond to the three figures.

Caution: Be careful with your algorithm so it finishes rapidly.

Sample Input

3 12 2 2 3
7 70 3 14 10 35
2 84 3 3 4 14
4 35 2 7 5
3 20 2 5 4
3 6 1 1
4 6 1 1
1 6 1 1
8600 8600 3 1 10 100
0

Sample Output

3517.6
2624.3
4987.7
3224.9
3488.4
3000.0
3000.0
7000.0
2000.0

Hint

Source


题意:将一个半径为1000的圆平分为n份,用有效点组成m个类三角形,有效点为给出的d个数字中任意一个数的倍数,问m个类三角形中周长最大值得最小值为多少

解题思路:二分+验证即可


#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <string>  
#include <algorithm>  
#include <map>  
#include <set>  
#include <stack>  
#include <queue>  
#include <vector>  
#include <bitset>  
#include <functional>

using namespace std;

#define LL long long  
const int INF = 0x3f3f3f3f;

int n, m, d;
int vis[100005], a[100005], cnt;
double x[100005];

int check(double k)
{
	for (int i = 0; i < cnt / 2; i++)
	{
		int cnt = 1;
		double sum = 0;
		for (int j = i + 1; a[j] - a[i] < n; j++)
		{
			if (sum + x[a[j] - a[j - 1]] <= k) sum += x[a[j] - a[j - 1]];
			else cnt++, sum = 0;
		}
		if (cnt <= m) return 1;
	}
	return 0;
}

int main()
{
	while (~scanf("%d%d%d", &m, &n, &d) && m)
	{
		memset(vis, 0, sizeof vis);
		cnt = 0;
		for (int i = 0; i < d; i++)
		{
			int k;
			scanf("%d", &k);
			for (int j = k; j <= n; j += k) vis[j] = 1;
		}
		for (int i = 1; i <= n; i++)
		{
			if (vis[i]) a[cnt++] = i, a[cnt++] = i + n;
			x[i] = 2000 * sin(acos(-1.0) * i / n);
		}
		sort(a, a + cnt);
		double l = 0, r = 2000 * acos(-1.0);
		while (r - l > 1e-8)
		{
			double mid = (l + r) / 2;
			if (check(mid)) r = mid;
			else l = mid;
		}
		printf("%.1lf\n", l + 2000);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值