问题描述
C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流。为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信。
现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
输入格式
输入的第一行包含三个整数n, m, k,分别表示村民的户数、备选的邮局数和要建的邮局数。
接下来n行,每行两个整数x, y,依次表示每户村民家的坐标。
接下来m行,每行包含两个整数x, y,依次表示每个备选邮局的坐标。
在输入中,村民和村民、村民和邮局、邮局和邮局的坐标可能相同,但你应把它们看成不同的村民或邮局。
接下来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
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。
对于60%的数据,1<=m<=20;
对于100%的数据,1<=n<=50,1<=m<=25,1<=k<=10。
题目解析:刚拿到题的时候感觉提示好像有点问题吧,怎么会是搜索,但是真正做的时候却明显感觉是多重循环的暴力,稍做剪枝,但是这道题我却做了大概不太到一天的时间,太惨了,啊啊啊啊啊
我却感觉这道题肯定是动态的问题,但是现在试过还是不太好处理,网上的结题报告暂时还没有,之后自己写一个。。。
//一定注意二维数组如果开小了的话,一般不会报错,这么简单的一道题我竟然弄了半天,愁。。。 #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> #define N 10010 using namespace std; int k,vis[55],tmpvis[55],mark[55]; int n, m; double dis[55][55]; double sum=9999999999.0; struct T{ int x, y; }post[55],vill[55]; void dfs(int node,int count,double tmpsum,double tmpdis[55]){//node是哪个记录邮局 ,count记录建立邮局个数 tmpsum记录当前的全部距离之和 //tmpdis 记录每个用户和邮局的最小距离 if( k-1-count>m-1-node) return ;//剪枝 之后的节点如果不够||tmpsum>=sum double newdis[55]; if(node+1<m) dfs(node+1,count,tmpsum,tmpdis);//忽略本邮局,建立下一个邮局 for(int i=0;i<n;i++)//记录下当前的数组情况 newdis[i] = tmpdis[i]; if(count==k-1){//出口,条件满足 tmpvis[count]=node; for(int i=0;i<n;i++){//更新最小值 if(newdis[i]>dis[ node ][i]){ int temp=tmpsum; tmpsum=tmpsum-newdis[i]+dis[ node ][i]; newdis[i]=dis[ node ][i]; } } if(tmpsum<sum){//更新输出最小值 sum=tmpsum; for(int i=0;i<k;i++){ vis[i]=tmpvis[i]; } } return ; } tmpvis[count]=node; //加入新的邮局节点 int mark1=1,mark2=1; //mark1==1说明为第一次,不可忽略,Mark2==1说明加入该点之后没有发挥作用 ,但是加入这两个标记位之后感觉好像有些情况是不对的,但是测试没有问题 ,并且没有改变90%超时的问题 if(count==0){ //如果是建立第一个邮局,初始化邮局到用户距离数组tmpdis和最小值 for(int i=0;i<n;i++){ tmpsum+=dis[ node ][i]; newdis[i]=dis[ node ][i]; } mark1=0; } else{//判断是否有距离新加的节点更近的节点,如果有加入并且更新 for(int i=0;i<n;i++){ if(newdis[i]>dis[ node ][i]) { int temp=tmpsum; tmpsum=tmpsum-newdis[i]+dis[ node ][i]; newdis[i]=dis[ node ][i]; mark2=0; } } } ////////if(tmpsum>sum) return ;//不可以这样剪枝,因为即便现在比sum大了,但是之后可能遇到更短的节点,一样可以更小 if(!(mark1&&mark2)) if(node+1<m) dfs(node+1,count+1,tmpsum,newdis ); return ; } int main (){ while(~scanf("%d%d%d",&n,&m,&k)){ sum=9999999999.0; for(int i=0;i<n;i++) scanf("%d%d",&vill[i].x,&vill[i].y); for(int i=0;i<m;i++){ scanf("%d%d",&post[i].x,&post[i].y); for(int j=0;j<n;j++){ dis[i][j]=sqrt( pow(vill[j].x-post[i].x,2)+pow(vill[j].y-post[i].y,2) ); } } double tmpdis[55]; dfs(0,0,0,tmpdis); for(int i=0;i<k;i++) printf("%d ",vis[i]+1); cout<<endl; } return 0; }