bfs最短路+dp(FZU 2186)

52 篇文章 0 订阅
23 篇文章 0 订阅

Problem 2186 小明的迷宫

Accept: 45    Submit: 138
Time Limit: 1000 mSec    Memory Limit : 32768 KB

Problem Description

小明误入迷宫,塞翁失马焉知非福,原来在迷宫中还藏着一些财宝,小明想获得所有的财宝并离开迷宫。因为小明还是学生,还有家庭作业要做,所以他想尽快获得所有财宝并离开迷宫。

Input

有多组测试数据。

每组数据第一行给出两个正整数n,m(0<n,m<=100)。代表迷宫的长和宽。

接着n行,每行m个整数。正数代表财宝(财宝的个数不超过10);负数代表墙,无法通过;0代表通道。

每次移动到相邻的格子,所花费的时间是1秒。小明只能按上、下、左、右四个方向移动。

小明的初始位置是(1,1)。迷宫的出口也在(1,1)。

Output

输出获得所有财宝并逃出迷宫所花费的最小时间,如果无法完成目标则输出-1。

Sample Input

3 3
0 0 0
0 100 0
0 0 0
2 2
1 1
1 1

Sample Output

44


思路:先求出任意两个宝藏之间的最短路,然后进行dp,dp[i][S]表示当前在i个宝藏,已经访问的宝藏集合为S的最小时间

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

typedef long long LL;

const int MAXN=105;
const int MAXM=110;
const int MAXNODE=25010;
const int MOD=1000000;
const int INF=0x3f3f3f3f;

typedef pair<int,int> pii;

int move[4][2]= {1,0,0,1,-1,0,0,-1};

int N,M,K,a[MAXN][MAXN],dis[MAXN][MAXN],dist[MAXN][MAXN];
int dp[15][2500];
bool vis2[MAXN][MAXN];

struct Point
{
    int x,y;
} p[15];


int DFS(int x,int s)
{
    int& ans=dp[x][s];
    if(ans!=-1) return ans;
    if(s+1==(1<<K)) return ans=dist[0][x];
    ans=INF;
    for(int i=0; i<K; i++) if(!(s&(1<<i))&&dist[i][x]!=INF)
        {
            int ret=DFS(i,s|(1<<i));
            if(ret!=INF) ans=min(ans,ret+dist[i][x]);
        }
    return ans;
}

int get_dist(int sx,int sy,int ex,int ey)
{
    memset(dis,0,sizeof(dis));
    memset(vis2,0,sizeof(vis2));
    queue<Point> q;
    q.push((Point)
    {
        sx,sy
    });
    vis2[sx][sy]=1;
    while(!q.empty())
    {
        Point tmp=q.front();
        q.pop();
        int x=tmp.x,y=tmp.y;
        if(x==ex&&y==ey) return dis[x][y];
        for(int i=0; i<4; i++)
        {
            int X=x+move[i][0],Y=y+move[i][1];
            if(X>0&&X<=N&&Y>0&&Y<=M&&a[X][Y]>=0&&!vis2[X][Y])
            {
                vis2[X][Y]=1;
                dis[X][Y]=dis[x][y]+1;
                q.push((Point)
                {
                    X,Y
                });
            }
        }
    }
    return INF;
}

int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        K=0;
        for(int i=1; i<=N; i++)
            for(int j=1; j<=M; j++)
            {
                scanf("%d",&a[i][j]);
                if(i==1&&j==1||a[i][j]>0) p[K++]=(Point)
                {
                    i,j
                };
            }
        if(a[1][1]<0)
        {
            printf("-1\n");
            continue;
        }
        for(int i=0; i<K; i++)
            for(int j=i; j<K; j++) dist[i][j]=dist[j][i]=get_dist(p[i].x,p[i].y,p[j].x,p[j].y);
        memset(dp,-1,sizeof(dp));
        int ans=DFS(0,1);
        if(ans==INF) printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值