DFS.04-海贼王之伟大航路

题目描述

:路飞他们伟大航路行程的起点是罗格镇,终点是拉夫德鲁
---------------因为伟大航路上的气候十分异常,所以来往任意两个岛屿之间的时间差别很大,从A岛到B岛可能需要1天,而从B岛到A岛则可能需要1年。
---------------当然,任意两个岛之间的航行时间虽然差别很大,但都是已知的。
现在假设路飞一行从罗格镇(起点)出发,遍历伟大航路中间所有的岛屿(但是已经经过的岛屿不能再次经过),最后到达拉夫德鲁(终点)。假设他们在岛上不作任何的停留,请问,他们最少需要花费多少时间才能到达终点?

思路

DFS,寻找最小时间,重点是把岛的连接顺序写明白
剪枝比较好想,预判时间,是否走过
要走的第一个岛和最后一个岛都是固定的

WA代码(第一次写出来的

#include<stdio.h>
#include<cmath>
#include<cstring>
using namespace std;

int island[8][8];
int mintime =1<<30;
int roadtime,islandN;
int visited[8];

void dfs(int i,int j,int num){
 
 if(visited[i])//已走过 
    return;
 
 if(num==islandN-1){
   roadtime+=island[i][islandN];//最后一个岛固定的 
   mintime=min(roadtime,mintime);
   }
 if(roadtime+island[i][j]>mintime)//预判 不应该是island[i][j]
    return;

 for(;i<islandN;++i){
   for(;j<islandN;++j){//!就是这里没有考虑岛屿的顺序关系导致 W A
       visited[i]=1;
       roadtime+=island[i][j];
       dfs(i,j,num++);  
       roadtime-=island[i][j];
       visited[i]=0;
      }
    }
}

int main(){
 scanf("%d",&islandN);
 for(int i=0;i<islandN;++i){
  for(int j=0;j<islandN;++j)
     scanf("%d",&island[i][j]);
  printf("\n");
 }
 memset(visited,0,sizeof(visited));
 int num=0;
 
 dfs(0,0,num);
 
 printf("%d",mintime);
}
return 0;
}

WA分析

在DFS的循环里,我的代码在判断一个岛有没有走过的时候,没有考虑连接关系
visited [ i ][ j ] = 1 ;只是把这个岛标记成了走过,并不能判断是从哪个岛来到这个岛的
剪枝的时候顺序也有问题
输入案例,结果为30,10+20+0=30;全部为第一个岛的时间关系

AC代码

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
int island[20][20];
int mintime=1<<30;//记录最短的路径
int totaltime=0;//记录目前为止总共走了多少
int visited[20];//记录第i个岛屿是否走过
int n;
int guo=0;//记录走过了哪些岛屿 第i个岛屿如果走过则guo中加上2的i次方
int time[65536][20];//time[i][j]记录已经走过i岛屿(i用二进制表示**所有**走过的岛屿)到达j的最短距离

void dfs(int s,int c){//s表示已经走过了s个岛屿(数量),c表示目前在岛屿c
     
     if(s==n-1)
        mintime=min(totaltime+island[c][n-1],mintime);//最后一个岛固定
     
     for(int i=1;i<n-1;i++){
         
        if(!visited[i]){//未走过
           
           int q=guo+pow(2,i);//q:所有走过岛(包括i)的二进制表达,guo+=也可以,简写
         
           if(totaltime+island[c][i]>=time[q][i])
              continue;//减支搜索 全局范围 走到C岛比目前已知的最短时间长则无需继续搜索
   
           time[q][i]=totaltime+island[c][i];//更新最小值
           visited[i]=1;
           guo+=pow(2,i);
           totaltime+=island[c][i];   
           dfs(s+1,i);//表示岛之间的连接关系
           totaltime-=island[c][i];
           guo-=pow(2,i);//回溯
           visited[i]=0;
       }
    }
}

int main(){
   for(int i=0;i<65535;i++)
      for(int j=0;j<20;j++)
          time[i][j]=1<<30;
   cin>>n;
   for(int i=0;i<n;i++)
      for(int j=0;j<n;j++)
          cin>>island[i][j];
 memset(visited,0,sizeof(visited));
 visited[0]=1;
 guo+=1;
 dfs(1,0);
 cout<<mintiem<<endl;
 return 0;
}

心得

  1. dfs函数传达了岛的顺序( s , c )
  2. time[ i ][ j ]二维函数,记录所有走过岛到 c岛 的最小时间,
    超强剪枝,全局范围包含所有搜索情况
  3. 二进制表示不会发生数字相同的情况
  4. visited[ i ]表示在这个搜索分支中有哪些岛走过了
  5. 没错,看的又是别人的代码,自己只能WA,道阻且长
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值