历届试题 邮局(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 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走 ...
随机推荐
- 学习笔记-java IO流总结 转载
1.什么是IO Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列.Java的I/O流提供了读 ...
- jsp 文件下载
有的时候一个模板的下载,这种简单的下载服务端已存在文件功能,就可以方便的通过jsp文件下载的方式来轻松实现. //jsp 页面 js /** * 导出角色 */ function exportRole ...
- JVM 内存设置大小(Xms Xmx PermSize MaxPermSize 区别)
Eclipse崩溃,错误提示:MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) sp ...
- linux强制踢出已登录的用户及本地用户
方法一: pkill -kill -t pts/0 方法二: fuser -k /dev/pts/0 你也可以给他发送关闭信息然后关闭 echo "你被管理员踢出了" > / ...
- mysql中having和where区别?
having和where有相似之处但也有区别,都是设定条件的语句. 在查询过程中,聚合语句(sum,min,max,avg,count),要比having子句有限执行. 在查询过程中,要先执行wher ...
- swift-新手必看的基础部分
Swift 是一门开发 iOS, OS X 和 watchOS 应用的新语言.然而,如果你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的很多内容都是你熟悉的. 常量和变量 ...
- 4.几个「不难但却很有用」的 Git 技能点
阅读 Git 原理详解及实用指南 记录 tag:不可移动的 branch tag 是一个和 branch 非常相似的概念,它和 branch 最大的区别是:tag 不能移动.所以在很多团队中,tag ...
- copy and rename a file multiple times using Matlab
for file.txt***********n=10;fileinfo=importdata('file.txt');for i=1:nfilename=sprintf('file_%d.txt', ...
- 【微软2017年预科生计划在线编程笔试 A】Legendary Items
[题目链接]:https://hihocoder.com/problemset/problem/1489 [题意] 每轮游戏; 你一开始有p的概率获得超神标记; 如果这轮游戏你没获得超神标记; 那么你 ...
- 【codeforces 796B】Find The Bone
[题目链接]:http://codeforces.com/contest/796/problem/B [题意] 一开始骨头在1号位置; 然后有m个洞,给出洞的下标; 然后有k个交换操作; 如果骨头到洞 ...