历届试题 邮局

<span style="font-family: 微软雅黑, 黑体, 宋体; background-color: rgb(255, 255, 255);"></span>
问题描述
  C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流。为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信。

  现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
输入格式
  输入的第一行包含三个整数n, m, k,分别表示村民的户数、备选的邮局数和要建的邮局数。
  接下来n行,每行两个整数x, y,依次表示每户村民家的坐标。
  接下来m行,每行包含两个整数x, y,依次表示每个备选邮局的坐标。
  在输入中,村民和村民、村民和邮局、邮局和邮局的坐标可能相同,但你应把它们看成不同的村民或邮局。
输出格式
  输出一行,包含k个整数,从小到大依次表示你选择的备选邮局编号。(备选邮局按输入顺序由1到m编号)
样例输入
5 4 2
0 0
2 0
3 1
3 3
1 1
0 1
1 0
2 1
3 2
样例输出
2 4
数据规模和约定
  对于30%的数据,1<=n<=10,1<=m<=10,1<=k<=5;
  对于60%的数据,1<=m<=20;
  对于100%的数据,1<=n<=50,1<=m<=25,1<=k<=10。
1.0s刚刚好。之前只能过八个,优化也就是以前dfs习惯 先保存状态然后再dfs 后面又还原状态 看了人家的代码学会了把保存的状态的数组传递下去就可以不用再还原  节约了一点时间。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double INF = 100000000000;
int n, m, k;
struct node{
	int x, y;
}home[51],post[30];
double getjl(node a, node b)
{
	return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
double pay[51][30]; //保存任意村子和邮局的距离 
double ans;
int useAns[11];
int use[11];
double s[51];
void dfs(int xb, int len, double s[],double sum)
{
	if(len==k)
	{
		if(sum < ans)
		{
			ans = sum;
			for(int i=0; i<k; i++)
			{
				useAns[i] = use[i];
			}
		}
		return ;
	}
	int p = m - xb + 1 + len;
	if(p<k)return;
	if(p>k)
    	dfs(xb+1, len, s, sum);
	if(len==0)
	{
		for(int i=1; i<=n; i++)
		{	
			sum += pay[i][xb];
			s[i] = pay[i][xb];
		}
		use[len] = xb;	
		dfs(xb+1, len+1, s, sum);
	}else{
		double b = 0;
		bool pd =false;
		double scopy[55];
		for(int i=1; i<=n; i++)
		{
			if(s[i] > pay[i][xb])
			{
				pd = true;
				scopy[i] = pay[i][xb];
			}else{
				scopy[i] = s[i];
			}
			b += scopy[i];
		}
		if(pd)
		{
			use[len] = xb; 
			dfs(xb+1, len+1, scopy, b);	
		}
	}
	
}
int main()
{
	scanf("%d %d %d", &n ,&m, &k);
	int i, j;
	for(i=1; i<=n; i++)
	{
		scanf("%d %d", &home[i].x, &home[i].y);
	}
	for(i=1; i<=m; i++)
	{
		scanf("%d %d", &post[i].x, &post[i].y);
		for(j=1; j<=n; j++)
		{
			pay[j][i] = getjl(home[j], post[i]);
		} 
	}
	ans = INF;
	dfs(1, 0, s, 0);
	printf("%d",useAns[0]);
	for(i=1; i<k; i++)
	{ 
		printf(" %d",useAns[i]);
	}
	printf("\n");
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值