zoukankan      html  css  js  c++  java
  • 蓝桥杯--- 历届试题 邮局 (深搜+暴力)(动态待解决)

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


  • 相关阅读:
    jquery.validate.js【简单实用的表单验证框架】
    velocity.js实现页面滚动切换效果
    站在巨人的肩膀上——制作酷炫web幻灯片
    简单说说随机打乱数组的方法
    JS数据结构之BinarySearchTree
    做一个extjs的扩展
    【OneAPM】极客编程挑战#025:发挥想象生成漂亮炫酷的SVG动画效果
    将博客搬至CSDN
    练习作品7:批量做字库 识别码
    联系作品6 模版打印 奖状
  • 原文地址:https://www.cnblogs.com/zswbky/p/5431944.html
Copyright © 2011-2022 走看看