蓝桥杯--- 历届试题 邮局 (深搜+暴力)(动态待解决)

来源:互联网 发布:北京11选5遗漏数据查询 编辑:程序博客网 时间:2024/06/16 07:45

问题描述
  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。


题目解析:刚拿到题的时候感觉提示好像有点问题吧,怎么会是搜索,但是真正做的时候却明显感觉是多重循环的暴力,稍做剪枝,但是这道题我却做了大概不太到一天的时间,太惨了,啊啊啊啊啊


我却感觉这道题肯定是动态的问题,但是现在试过还是不太好处理,网上的结题报告暂时还没有,之后自己写一个。。。


//一定注意二维数组如果开小了的话,一般不会报错,这么简单的一道题我竟然弄了半天,愁。。。 #include <iostream>#include <stdio.h>#include <queue>#include <math.h>#include <string.h>#define N 10010using 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;}


0 1
原创粉丝点击