【每日刷题】P1515 旅行题解

这是很小白很新手的题解~大佬们可以不看了orz

旅行

题目描述

你要进行一个行程为7000KM的旅行,现在沿途有些汽车旅馆,为了安全起见,每天晚上都不开车,住在汽车旅馆,你手里现在已经有一个旅馆列表,用离起点的距离来标识,如下:

0, 990, 1010, 1970, 2030, 2940, 3060

3930, 4060, 4970, 5030, 5990, 6010, 7000

但在出发之前可能还要增加一些旅馆。

现在旅行社为了节约成本,要求每天至少行驶A公里,国家旅行社为了安全起见,要求每天最多只能行驶B公里。

你想知道一共有多少种旅行方案。

输入格式

第一行输入A,第二行输入B,第三行输入N(0≤N≤20),表示在出发之前又新增N个汽车旅馆;接下来N行,每行一个整数m,表示旅馆离起点的距离(0<m<7000)。注意:没有任意两个旅馆在同一位置。

输出格式

输出一共有多少种旅行方案。

样例 #1

样例输入 #1

500
1500
0

样例输出 #1

64

C语言

两种做法,一种是暴力DFS,一种是贪心思想的递推

1.DFS

在说深度优先搜索解法前,如果不是很了解的可以去百度一下,其实总的来说就是

从初始节点出发,按预定的顺序扩展到下一个节点,然后从下一节点出发继续扩展新的节点,不断递归执行这个过程,直到某个节点不能再扩展下一个节点为止。此时,则返回上一个节点重新寻找一个新的扩展节点。如此搜索下去,直到找到目标节点,或者搜索完所有节点为止。

也就是在一条路上,我是否可以在这条路上一直走下去,如果走不通,那我就返回原来的节点,换个方向,再沿着一条路走下去,直到成功。

然后我们回到这道题

由于新增的旅馆是乱序的,所以在输入后要记得排序噢~可以采取很多排序方法,但是感觉用快排的板子会比较简单,可以把qsort整个自定义函数记下来当成c语言快排的模板噢~如果考试可以带纸质资料的话建议打印下来?

我们假设我们现在已经在第now个旅馆休息了,我们要继续走下去,那么我们就从它后面的那个旅馆开始枚举,看下一个旅馆符不符合我能停下来休息的条件,如果符合那我们就走到第i个旅馆,不符合的话就继续列举查询,直到找到我可以歇脚的旅馆。而这条路什么时候走不通呢,就是当我们的now是最后一个节点的时候,就是说我们已经到达了终点,所以我们开始返回,在dfs里面可以称为回溯,返回上一个结点后我们换个方向走,直到所有的都走完。

#include<stdio.h>

int dis[40]={0,990,1010,1970, 2030, 2940, 3060,3930, 4060, 4970, 5030, 5990, 6010, 7000};
int ans;
int a,b,n;
int m;
int k;

void qsort(int a[],int l,int r){
	int temp;
	int mid=a[(l+r)/2];
	int i=l;
	int j=r;
	while(i<=j){
		while(a[i]<mid)i++;
		while(a[j]>mid)j--;
		if(i<=j){
			temp=a[i];
			a[i]=a[j];
			a[j]=temp;
			i++;
			j--;
		}
	}
	if(i<r)qsort(a,i,r);
	if(j>l)qsort(a,l,j);
}
void dfs(int now){
	if(now==k-1){//k-1就是最后一个旅馆
		ans++;
		return;//回溯到上一个dfs的for循环中继续列举
	}
	for(int i=now+1;i<=k-1;i++){
		if(dis[i]-dis[now]>=a&&dis[i]-dis[now]<=b){//遇到符合的就跳到进入这个旅馆的dfs
			dfs(i);
		}
	}
}
int main(){
	k=14;
	scanf("%d %d",&a,&b);
	scanf("%d",&n);
	while(n--){
		scanf("%d",&m);
		dis[k++]=m;
	}
	qsort(dis,0,k-1);
	dfs(0);
	printf("%d\n",ans);
}

在这里我是把qsort函数写出来让你们理解一下,如果你们理解了快排,可以直接用c语言库中的qosrt函数,

#include<stdio.h>
#include<stdlib.h>
int dis[40]={0,990,1010,1970, 2030, 2940, 3060,3930, 4060, 4970, 5030, 5990, 6010, 7000};
int ans;
int a,b,n;
int m;
int k;

int cmp_int(const void* e1, const void* e2)
{
    return *(int*)e1 - *(int*)e2;
}
void dfs(int now){
    if(now==k-1){//k-1就是最后一个旅馆
        ans++;
        return;//回溯到上一个dfs的for循环中继续列举
    }
    for(int i=now+1;i<=k-1;i++){
        if(dis[i]-dis[now]>=a&&dis[i]-dis[now]<=b){//遇到符合的就跳到进入这个旅馆的dfs
            dfs(i);
        }
    }
}
int main(){
    k=14;
    scanf("%d %d",&a,&b);
    scanf("%d",&n);
    while(n--){
        scanf("%d",&m);
        dis[k++]=m;
    }
    qsort(dis, k-1, sizeof(dis[0]), cmp_int);//这里的参数可以去看一下我下面推的这篇博客
    dfs(0);
    printf("%d\n",ans);
}

关于qsort可以看一下这个这篇博客https://blog.csdn.net/chuxinchangcun/article/details/120046062

2.递推

由于新增的旅馆是乱序的,所以在输入后要记得排序噢~可以采取很多排序方法,但是感觉用快排的板子会比较简单,可以把qsort整个自定义函数记下来当成c语言快排的板子噢~

我们可以这么想,假设我们现在前面已经都休息过,然后现在已经到了第i个旅馆休息,那么我们在到达第i个旅馆的方案数是不是就是他上一个假定的休息的地方的方案数,而上一个休息的地方是不是只要满足它们之间的距离是>=A且<=B区间的旅馆数,那么对于第i个旅馆而言,它的方案数就是这些旅馆数之和!所以我们就直接枚举就好啦

#include<stdio.h>

int dis[40]={0,990,1010,1970, 2030, 2940, 3060,3930, 4060, 4970, 5030, 5990, 6010, 7000};
int ans[40];

void qsort(int a[],int l,int r){
	int temp;
	int mid=a[(l+r)/2];
	int i=l;
	int j=r;
	while(i<=j){
		while(a[i]<mid)i++;
		while(a[j]>mid)j--;
		if(i<=j){
			temp=a[i];
			a[i]=a[j];
			a[j]=temp;
			i++;
			j--;
		}
	}
	if(i<r)qsort(a,i,r);
	if(j>l)qsort(a,l,j);
}//快速排序模板
int main(){
	int a,b,n;
	int m;
	int k=14;
	scanf("%d %d",&a,&b);
	scanf("%d",&n);
	while(n--){
		scanf("%d",&m);
		dis[k++]=m;
	}
	qsort(dis,0,k-1);
	ans[0]=1;//第0个旅馆显然只有0→0这一种方案
	for(int i=1;i<=k-1;i++){
		for(int j=0;j<i;j++){//枚举第i个前面的旅馆数就好了
			if(dis[i]-dis[j]>=a&&dis[i]-dis[j]<=b){//满足题目要求的旅馆间的距离
				ans[i]+=ans[j];
			}
		}
	}
	printf("%d\n",ans[k-1]);//终点显然是7000
}

下面是C++写法

就是把排序直接用了sort

#include<bits/stdc++.h>

using namespace std;

int dis[40] = {0, 990, 1010, 1970, 2030, 2940, 3060, 3930, 4060, 4970, 5030, 5990, 6010, 7000};
int ans;
int a, b, n;
int m;
int k;

bool cmp(int a,int b){
	return a<b;
}
void dfs(int now) {
	if (now == k - 1) {
		ans++;
		return;
	}
	for (int i = now + 1; i <= k - 1; i++) {
		if (dis[i] - dis[now] >= a && dis[i] - dis[now] <= b) {
			dfs(i);
		}
	}
}
int main() {
	k = 14;
	cin >> a >> b >> n;
	while (n--) {
		cin>>m;
		dis[k++] = m;
	}
	sort(dis, dis+k-1,cmp);
	dfs(0);
	printf("%d\n", ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值