历届试题 邮局(dfs+剪枝)
现在给出了m个备选的邮局,请从中选出k个来,使得村民到自己家最近的邮局的距离和最小。其中两点之间的距离定义为两点之间的直线距离。
接下来n行,每行两个整数x, y,依次表示每户村民家的坐标。
接下来m行,每行包含两个整数x, y,依次表示每个备选邮局的坐标。
在输入中,村民和村民、村民和邮局、邮局和邮局的坐标可能相同,但你应把它们看成不同的村民或邮局。
0 0
2 0
3 1
3 3
1 1
0 1
1 0
2 1
3 2
对于60%的数据,1<=m<=20;
对于100%的数据,1<=n<=50,1<=m<=25,1<=k<=10。
感觉这道题还是很不错的,刚开始没怎么看数据量,写的代码超时了
超时思路:m个备用邮局,建k个,如果用1,0表示建跟不建,那么数组中就有k个1,m-k个0,所以全排列之后就是每一个方案,然后计算出每一组方案的话费,之后取最优花费,但是有的数据比较大,比如50,如果有10个邮局,那么方案就有很多很多,组合数公式算下来肯定崩,但是这个思路对于小的数据应该还是可以的,先上超时代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
double x,y;
}a[60],b[60];
int n,m,k,s[60],num[60];
double dis(int x,int y)
{
return sqrt((a[x].x-b[y].x)*(a[x].x-b[y].x)+(a[x].y-b[y].y)*(a[x].y-b[y].y));
}
double dfs()
{
double sum=0;
for(int i=0;i<n;i++)
{
double val=INF;
for(int j=0;j<m;j++)
{
if(s[j])
{
double d=dis(i,j);
val=min(val,d);
}
}
sum+=val;
}
return sum;
}
int main()
{
while(cin>>n>>m>>k)
{
memset(s,0,sizeof(s));
for(int i=0;i<n;i++)
cin>>a[i].x>>a[i].y;
for(int i=0;i<m;i++)
cin>>b[i].x>>b[i].y;
for(int i=0;i<k;i++)
s[i]=1;
int cnt;
double ans=INF;
do{
double si=dfs();
if(ans>si)
{
ans=si;
memset(num,0,sizeof(num));
cnt=0;
for(int i=0;i<m;i++)
if(s[i])
num[cnt++]=i;
}
}while(prev_permutation(s,s+m));
for(int i=0;i<k-1;i++)
printf("%d ",num[i]+1);
printf("%d\n",num[k-1]+1);
}
return 0;
}
</pre>AC思路(dfs+剪枝):dfs最重要的就是建立搜索树,这里每个点都有两种状态,如果直接暴力时间肯定很长,所以需要加上剪枝,我们可以将村子的住户还有备用邮局看作是两个集合,就像普利姆的思路一样,总的思路就是更新最短距离数组,我们先将所有的点全部连接在第一个备用邮局,也可以不连第一个,毕竟每个点有两种状态,如果第二个备用邮局到住户的距离足以更新最短距离数组,那就更新之后寻找下一个邮局,如果不足以更新最短距离数组,我们就直接放弃这个点,显然他是没有用的,找到k个邮局之后就判定一下话费,是否更短,如果是,更新序号数组
#include<iostream>
#include<stdlib.h>
#include<math.h>
using namespace std;
int n,m,k,j,c[55][2],y[27][2],d[12],f1,f2,f[55]={0};
float yc[27][55],s=1000000000;
int dfs(int t,int i,int o[12],float w[55],float sum)
{//t±íʾѰÕҵĵÚi¸öÓʾ֣¬t±íʾ±¸ÓÃÓʾֵıàºÅ
if(i<=m+1)
{
if(t==k)//ÕÒµ½ÁËk¸öÓʾ֣¬²¢ÇÒÏûºÄ¸üµÍ
{
if(sum<s)
{
s=sum;
for(j=0;j<k;j++)
d[j]=o[j];
}
}
else if(i<=m&&t<k)
{
float ww[55];//´æ´¢×î¶Ì¾àÀë
for(j=1;j<=n;j++)
ww[j]=w[j];//×î¶Ì¾àÀë¸´ÖÆ£¬Ã¿Ò»²½¶¼Òª½øÐÐ
dfs(t,i+1,o,w,sum);//Ò»¸öµãÓÐÁ½ÖÖ״̬£¬Õâ¸öÊDz»½¨Óʾֵģ¬
//½øÐÐÁËÕâÒ»²½£¬i²»²ÎÓë¸üÐÂ
f1=1,f2=0;//ÅжÏiÊÇ·ñ¿ÉÒÔʹÓÃ
if(!f[i])
{
o[t]=i;
if(t>0)
{
f2=1;//Èç¹ûi²»ÊǵÚ0¸öµã
for(j=1;j<=n;j++)
{
if(ww[j]>yc[i][j])
{
sum=sum-ww[j]+yc[i][j];//sum´¢´æ×ܵľàÀë
ww[j]=yc[i][j];
f1=0;//ww±»¸üеıê¼Ç
}
}
}
else
{
for(j=1;j<=n;j++)
{
sum+=yc[i][j];//¸Õ¿ªÊ¼Ê±È«²¿Á¬ÔÚµÚ1¸öµã¡£Ö®ºó¸üÐÂ
ww[j]=w[j]=yc[i][j];
}
}
if(f1&&f2)//¼ôÖ¦
{
f[i]=1;//²»ÊǵÚ0¸öµãÇÒ²»ÄܲÎÓë¸üÐÂ
dfs(t,i+1,o,w,sum);//Èç¹ûµÚi¸öÓʾֵ½ÆäËûn¸öµãµÄ¾àÀë¶¼±ÈwwÖеĴó£¬iÉáÆú
}
else
dfs(t+1,i+1,o,ww,sum);//µÚi¸öµã¿ÉÒÔ¸üÐÂww¾ÍʹÓøõã
}
}
}
}
int main()
{
int i,j,o[12];
float w[55],ww[55];
cin>>n>>m>>k;
for(i=1;i<=n;i++)
cin>>c[i][0]>>c[i][1];
for(i=1;i<=m;i++)
{
cin>>y[i][0]>>y[i][1];
for(j=1;j<=n;j++)
yc[i][j]=sqrt((c[j][0]-y[i][0])*(c[j][0]-y[i][0])+(c[j][1]-y[i][1])*(c[j][1]-y[i][1]));
}
dfs(0,1,o,w,0);
for(i=0;i<k;i++)
cout<<d[i]<<" ";
return 0;
}
历届试题 邮局(dfs+剪枝)的更多相关文章
- 算法笔记_178:历届试题 邮局(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流.为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己 ...
- Java实现 蓝桥杯 历届试题 邮局
问题描述 C村住着n户村民,由于交通闭塞,C村的村民只能通过信件与外界交流.为了方便村民们发信,C村打算在C村建设k个邮局,这样每户村民可以去离自己家最近的邮局发信. 现在给出了m个备选的邮局,请从中 ...
- 蓝桥杯练习系统历届试题 带分数 dfs
问题描述 100 可以表示为带分数的形式:100 = 3 + 69258 / 714. 还可以表示为:100 = 82 + 3546 / 197. 注意特征:带分数中,数字1~9分别出现且只出现一次( ...
- 蓝桥杯 历届试题 剪格子 dfs
历届试题 剪格子 时间限制:1.0s 内存限制:256.0MB 问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+ |10* 1|52| +--****--+ |20 ...
- 蓝桥杯 历届试题 幸运数 dfs
历届试题 幸运数 时间限制:1.0s 内存限制:256.0MB 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的"筛法"生成 . 首先从1开始写出自然数1,2, ...
- 蓝桥杯 历届试题 剪格子(dfs搜索)
历届试题 剪格子 时间限制:1.0s 内存限制:256.0MB 问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+ |* || +--****--+ ||* | ** ...
- 蓝桥杯-历届试题 剪格子(dfs)
历届试题 剪格子 时间限制:1.0s 内存限制:256.0MB 问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+|10* 1|52|+--**** ...
- 历届试题 危险系数-(dfs+记录路径)
历届试题 危险系数 问题描述 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点间可能因此会失去联系. 我 ...
- 蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索
问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走 ...
随机推荐
- 控制台——args参数的赋值方法
args参数的赋值方法有好几种,主要介绍两种. 外部传参的方法:先找到bin目录下的exe文件,并创建快捷方法,在目标后面追加参数. 控制台主函数入口实现方法 static void Main(str ...
- vim下阅读代码时标签跳转设置
1.在fedora14中的 /etc/vimrc下,加入如下几行,可根据源代码工程文件的结构来定 2. 在源代码工程内,输入如下命令 ctags -R 当前目录下将生成一个tags文件 3.查看源代码 ...
- Stanford coursera Andrew Ng 机器学习课程第二周总结(附Exercise 1)
Exercise 1:Linear Regression---实现一个线性回归 重要公式 1.h(θ)函数 2.J(θ)函数 思考一下,在matlab里面怎么表达?如下: 原理如下:(如果你懂了这道作 ...
- postfix 邮件中继配置
Postfix 配置邮件中继 A 邮件发送服务器B 邮件中继服务器 A. 配置发件服务器 # 开启转发规则 [root@Postfix ~]# vi /etc/postfix/main.cf tran ...
- Ubuntu无线转有线教程
本来想测试一下有线转无线的,奈何网卡不支持,所以就测试了一回无线转有线的测试!(真无聊,不过也算学习一下linux网桥的知识) ca0gu0@ub:~$ sudo brctl addbr br0 #添 ...
- Python_多线程1(创建线程,简单线程同步)
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法: threading.currentThread(): 返回当前的线程变量. threading.enumera ...
- python 模块学习——time模块
Python语言中与时间有关的模块主要是:time,datetime,calendar time模块中的大多数函数是调用了所在平台C library的同名函数, 所以要特别注意有些函数是平台相关的,可 ...
- 零基础学习Python培训,应该选择哪个培训班?
近几年中,Python一直是市场上最受欢迎的编程语言之一.它语法自然,入门简单,同时应用范围又极广,无论是大火的人工智能.大数据还是传统的web开发.自动化运维,Python都能够大展拳脚.根据职友集 ...
- ubuntu系统中java开发环境的搭建
Java环境可选择 Oracle 的 JDK,或是 OpenJDK,按http://wiki.apache.org/hadoop/HadoopJavaVersions中说的,新版本在 OpenJDK ...
- file.seek()/tell()-笔记
---------------------------------------------------------------------------------------------------- ...