试题 历届试题 邮局

一共有m个邮局从中选出k个邮局,对每个邮局我们有两种选择,一:选择这个邮局。二:不选择这个邮局。很显然我们直接用深搜(dfs)就行。(这里不明白dfs的也没关系,你可以看代码自己思考一下就明白了)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
struct node {
	int x,y;
};
node A[51];//记录村民坐标 
node B[26];//记录邮局坐标 
double l[51][26];//l[i][j]是 i号村民到j号邮局的距离 
double dp[51];//dp[i]记录当前选择的所有邮局中,i到所有选择的邮局中的最短的距离
// 既假设选择了 1号和2号  i到1 的距离为3 ,i到2的距离为4,那么所有选择的邮局分别是1,和2,那么
//dp[i]就等于其中最小的哪一个既dp[i]=1; 
int n,m,k;
double MAXV=10000001;
vector<int> ve;//存放最佳的邮局号码 
vector<int> v;//临时的邮局号码,再dfs里面用到 
// index 记录当前的邮局号码,ans记录选择了几个邮局了,
//sum记录村民到自己家最近的邮局的距离最小的和
//dp[i]记录当前选择的邮局中i号村民到选择的邮局的最短距离
void dfs(int index,int ans,double sum,double dp[]){
	if(ans==k){//函数的终点 即选择了K个数了 
		if(sum<MAXV){
			ve=v;
			MAXV=sum;
			return ;
		}
		return;
	}
	if(index>m||ans>k) return ;//这个终点不能再if(ans==k)前面 因为当index==m+1时正好有ans==k,
                             	//     那就不能执行if(ans==k)了 
	double f[56];//新建一个数组f 以为对一个邮局我们可以选择也可以不选择,如果不选择那么
	             //dp[i]就保持原样 不能改变 
	for(int i=1;i<=n;i++) {
		if(dp[i]>l[i][index])f[i]=l[i][index];//改变f[i] 
		else f[i]=dp[i];
	};
	double num=0;
	for(int i=1;i<=n;i++) num+=f[i];
	v.push_back(index);//选择该邮局则把邮局的号码存进去 
	dfs(index+1,ans+1,num,f);//选择该邮局继续往下执行  dp的位置换成f因为我们选择了该邮局所以要用f 
	v.pop_back();// 不选择该邮局则把该邮局踢出去 
	dfs(index+1,ans,sum,dp);//注意这里仍然时dp以为我们不选择该邮局则dp不用更新 
}
int main(){
	fill(dp,dp+51,1000001);//把距离初始化成一个特别大的数 
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&A[i].x,&A[i].y);
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d",&B[i].x,&B[i].y);
		for(int j=1;j<=n;j++){
		l[j][i]=sqrt(pow(A[j].x-B[i].x,2)+pow(A[j].y-B[i].y,2) );	
		}
	}
	dfs(1,0,0,dp);
	for(int i=0;i<ve.size();i++){
		printf("%d ",ve[i]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值