B - Stealing Harry Potter's Precious BFS +佛洛依德 + DFS

题意 :
给你一个迷宫,最多有四个所需要拿走的物品, 要求你从起点出发,花费最小的路程取得K个物品。问这个最小路程是多少
思路:
因为是要去取物品,然后就会有一个路程(权值),那么就可以用最短路算法来做,做到一半的时候会发现,如果要以单源最短路来做的话,就需要跑K次的最短路,因为你每拿到一件物品,你的起点就会改变。所以说我选择folry(不知道是不是这个单词 = =)因为K最多为4 , 最坏的情况下也就是4^3 的复杂度。 然后求出任意两点的最短路后,就DFS一下的事,求从起点出发,经过K个点后所取得的最小权值即为答案。

#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
#include<cstdio>
using namespace std;
 const int maxn = 105 ;
 char arr[105][105] ;
 int  n , m , coun , cnt = 0 ;
 int mpt[105][105] ;
 int ans = 0 ;
  int vis[maxn][maxn] = {0};
  int line[10] ;
  int dx[] = {0,0,1,-1} ;
  int dy[]=  {1,-1,0,0} ;
  struct node{
 int x , y ;
 int cost ;
  };
void fory(int x){

for(int k = 0 ; k <= x ; k++)
    for(int i = 0 ; i<= x ; i++)
    for(int j = 0 ; j <= x ; j++)
    mpt[i][j] = min(mpt[i][k] + mpt[k][j] , mpt[i][j]) ;
     for(int i = 0 ; i <= x ; i++) mpt[i][i] = 0x3f ;
}



queue<node> q ;
void init(){
    coun = 0 ;ans = 999999 ;
    cnt = 0;
memset(mpt , 0x3f , sizeof(mpt)) ;
memset(line , 0 , sizeof(line)) ;
memset(arr , 0 , sizeof(arr)) ;
memset(vis , 0 , sizeof(vis)) ;
}
int BFS(int x , int y , int sx , int sy){
 while(!q.empty()) q.pop() ;
  node s1 , s2 , s3 ;
  s1.cost = 0 , s1.x = x , s1.y = y ;
  vis[x][y] = 0 ;
  q.push(s1) ;
  while(!q.empty()){
      s2 = q.front() ; q.pop() ;
      int xx = s2.x , yy = s2.y ;
      for(int i = 0 ; i < 4 ; i++){
          int xxx = xx + dx[i] ;
          int yyy = yy + dy[i] ;
        if(xxx < n && xxx >= 0 && yyy < m && yyy >= 0 && vis[xxx][yyy] == 0 && arr[xxx][yyy] != '#'){
            vis[xxx][yyy] = 1 ;
            s3.cost = s2.cost + 1 ; s3.x = xxx , s3.y = yyy ;
            q.push(s3) ;
            if(xxx == sx && yyy == sy) return coun = s3.cost ;
        }
      }
  }
   return -1 ;
}
void DFS(int x , int cost , int k  , int tot ){
   line[x] = 1 ;
   if(tot == k ) ans = min(ans , cost) ;
   for(int i = 0 ; i <= k ; i++){
    if(line[i] == 0 && i != x){
         DFS(i , mpt[x][i] + cost , k , tot + 1) ;
         line[i] = 0 ;
    }
   }
}
int main(){

  while(scanf("%d %d",&n,&m) != EOF){
        if(n + m == 0) break ;
        int  key = 0 ;
      init() ;
      int AX = -1 , AY = -1 ;
      for(int i = 0 ; i <n ; i++){
            scanf("%s",&arr[i]) ;
            for(int j = 0 ; j < m ; j++){
                 if(AX != -1 && AY != -1) break ;
                 if(arr[i][j] == '@') AX = i , AY = j ;
            }
      }
      int k , x[10] , y[10];
      cin >> k ;
      for(int i = 1 ; i <= k ; i++){
        scanf("%d %d",&x[i],&y[i]) ;
         for(int j = 1 ; j < i ; j++){
                coun = 0 ;
           memset(vis , 0 , sizeof(vis)) ;
           if(BFS(x[i]-1 , y[i]-1 , x[j] - 1,y[j] - 1) == -1 ) mpt[i][j] = mpt[j][i] = 0x3f ;
           else {
                    mpt[i][j] = coun  ;
                    mpt[j][i] =coun  ;
           }
         }
      }
      for(int i = 1  ; i <= k ; i++){
          memset(vis , 0 , sizeof(vis)) ;
          coun = 0 ;
          if(BFS(x[i] -1 , y[i]-1 , AX , AY) == -1 ) key = 1 ;
          else {
             mpt[0][i] = mpt[i][0] = coun ;
          }
      }

      if(key == 1) cout << "-1" << endl ;
      else {
            fory(k) ;
            memset(line , 0 , sizeof(line)) ;
            DFS(0 , 0 , k  + 1 ,1) ;
            cout << ans << endl ;
      }
  }

 return 0 ;
}
/*
4 3
#@#
...
.#.
.#.
4
2 1
2 3
4 1
4 3
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值