问题 1457: [蓝桥杯][历届试题]邮局
时间限制: 1Sec 内存限制: 128MB 提交: 136 解决: 25
题目描述
C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流。为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信。
现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
数据规模和约定
对于100%的数据,1< =n< =50,1< =m< =25,1< =k< =10。
输入
输入的第一行包含三个整数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
思路:
单词的枚举k个邮局肯定是会超时的。参考了被人博客,发现了新思路。
设状态为 当前枚举的是第x个备选邮局,有选和不选两种选择。 当前已经选了knum个邮局。当前的最小值是s。当前的每个村庄到某个邮局的最小值。
一种类似于最短路的松弛思想,一开始选第一个邮局时,让所有村庄和第一个邮局相连,然后不断枚举新的邮局,看新的邮局能否缩短距离,能的话就继续搜索。
剪枝的话需要注意如果剩余的备选邮局m-x数量小于仍需要安排的邮局k-knum,需要剪枝一下。
代码:
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#include<string.h>
#include<queue>
#include<stack>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=100+6;
#define mod 1000000007
#define INF 0x3f3f3f3f
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
int n,m,k;
struct node
{
int x;
int y;
} a[maxn],b[maxn];
double dist(node aa,node bb)
{
return sqrt((aa.x-bb.x)*(aa.x-bb.x)+(aa.y-bb.y)*(aa.y-bb.y));
}
int ans[maxn];
double len[maxn][maxn];
int step[maxn];
double maxx;
bool flag[maxn];
void dfs(int x,int knum,double s,double dis[])
{
//cout<<x<<endl;
//cout<<knum<<endl;
if(knum>k+1)
return ;
if(m-x<k-knum)
return ;//不够了
if(x>m+1)
return ;
if(knum==k+1)
{
//cout<<"ss"<<endl;
if(maxx>s)
{
maxx=s;
rep(i,1,k)
{
ans[i]=(step[i]);
}
}
return ;
}
double tmp[maxn];
rep(i,1,n)
{
tmp[i]=dis[i];
}
dfs(x+1,knum,s,tmp);//不选这个
if(flag[x])
return ;
step[knum]=x;
//cout<<x<<endl;
bool f1=0,f2=0;
if(knum==1)
{
rep(i,1,n)
{
tmp[i]=len[i][x];
s+=len[i][x];
}
f1=1;
//cout<<f1<<"rrrr"<<endl;
}
else
{
rep(i,1,n)
{
if(tmp[i]>len[i][x])
{
f2=1;
s+=len[i][x]-tmp[i];
tmp[i]=len[i][x];
}
}
}
if(!f1&&!f2)
flag[x]=1;
if(f1||f2)
{
dfs(x+1,knum+1,s,tmp);//选这个
}
return ;
}
int main()
{
cin>>n>>m>>k;
rep(i,1,n)cin>>a[i].x>>a[i].y;
rep(i,1,m)cin>>b[i].x>>b[i].y;//邮局
rep(i,1,n)
{
rep(j,1,m)
{
len[i][j]=dist(a[i],b[j]);
}
}
maxx=INF;
double dis[maxn];
memset(dis,-1,sizeof(dis));
dfs(1,1,0,dis);
for(int i=1; i<=k; i++)
{
cout<<ans[i]<<" ";
}
// cout<<endl;
return 0;
}