这是很小白很新手的题解~大佬们可以不看了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
在说深度优先搜索解法前,如果不是很了解的可以去百度一下,其实总的来说就是
![](https://i-blog.csdnimg.cn/blog_migrate/150328844787ecdbe9cceaac62e7a764.png)
从初始节点出发,按预定的顺序扩展到下一个节点,然后从下一节点出发继续扩展新的节点,不断递归执行这个过程,直到某个节点不能再扩展下一个节点为止。此时,则返回上一个节点重新寻找一个新的扩展节点。如此搜索下去,直到找到目标节点,或者搜索完所有节点为止。
也就是在一条路上,我是否可以在这条路上一直走下去,如果走不通,那我就返回原来的节点,换个方向,再沿着一条路走下去,直到成功。
然后我们回到这道题
由于新增的旅馆是乱序的,所以在输入后要记得排序噢~可以采取很多排序方法,但是感觉用快排的板子会比较简单,可以把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);
}