HDU 3681 二分+状压+BFS

题意

一个人要出逃,需要从F点出发,访问所有的Y点才可以成功出逃,这个人可以拥有一个能量为V的背包,每移动一格消耗1点能量,到达G点的时候可以补充满能量。问最少需要携带一个多小的背包,才能成功出逃。

题解

第一眼看见这道题的时候,想的只是一个普通的BFS。但是在用优先队列实现的时候出现了一些问题,不太好判断优先访问哪个点。倘若不进行优先访问的选择,允许重复访问同一个点,那么无论是时间上还是空间上都是不可承受的。
看了题解才意识到这道题不是一道普通的BFS题,ORZ。。二分背包容量,BFS计算两点之间最短路,状压DP计算某个背包容量是否可行。

代码

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 8200
#define EPS 1e-10
#define MOD 100000000

using namespace std;

struct Node {
    int x,y;
};
char mp[20][20];
int vis[20][20];
int dis[20][20][20][20];
int dp[20][67000];
int nodenum;
int dir[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
Node nodes[20];
int n,m;
int finalState;
int start;

void bfs(int x,int y) {
    memset(vis,false,sizeof(vis));
    queue<Node> que;
    Node first;
    first.x=x;
    first.y=y;
    que.push(first);
    dis[first.x][first.y][first.x][first.y]=0;
    W(!que.empty()) {
        Node front=que.front();
        que.pop();
        vis[front.x][front.y]=true;
        UP(i,0,4) {
            Node newnode=front;
            newnode.x+=dir[i][0];
            newnode.y+=dir[i][1];
            if(newnode.x>=n||newnode.y>=m||newnode.x<0||newnode.y<0)
                continue;
            if(vis[newnode.x][newnode.y])
                continue;
            if(mp[newnode.x][newnode.y]=='D')
                continue;
            dis[newnode.x][newnode.y][x][y]=dis[front.x][front.y][x][y]+1;
            que.push(newnode);
        }
    }
}

bool check(int v) {
    memset(dp,-1,sizeof(dp));
    dp[start][1<<start]=v;
    UP(k,0,1<<nodenum) {
        UP(i,0,nodenum) {
            if(dp[i][k]==-1||!(k&(1<<i)))
                continue;
            if((k&finalState)==finalState)
                return true;
            UP(j,0,nodenum) {
                if(i==j||(k&(1<<j)))
                    continue;
                int cost=dis[nodes[i].x][nodes[i].y][nodes[j].x][nodes[j].y];
                if(cost==-1||cost>dp[i][k])
                    continue;
                dp[j][k+(1<<j)]=max(dp[j][k+(1<<j)],dp[i][k]-cost);
                if(mp[nodes[j].x][nodes[j].y]=='G')
                    dp[j][k+(1<<j)]=v;
            }
        }
    }
    return false;
}

int main() {
    W(~scanf("%d%d",&n,&m)) {
        if(n==0&&m==0)
            break;
        memset(dis,-1,sizeof(dis));
        nodenum=0;
        finalState=0;
        UP(i,0,n) {
            scanf("%s",mp[i]);
            UP(j,0,m) {
                if(mp[i][j]=='F') {
                    start=nodenum;
                    finalState+=(1<<nodenum);
                    nodes[nodenum].x=i;
                    nodes[nodenum++].y=j;
                }
                if(mp[i][j]=='Y') {
                    finalState+=(1<<nodenum);
                    nodes[nodenum].x=i;
                    nodes[nodenum++].y=j;
                }
                if(mp[i][j]=='G') {
                    nodes[nodenum].x=i;
                    nodes[nodenum++].y=j;
                }
            }
        }
        UP(i,0,nodenum) {
            bfs(nodes[i].x,nodes[i].y);
        }
        int left=0,right=250;
        int ans=INF;
        W(left<=right) {
            int mid=(left+right)/2;
            if(check(mid)) {
                right=mid-1;
                ans=min(ans,mid);
            } else {
                left=mid+1;
            }
        }
        if(ans==INF) {
            puts("-1");
        } else {
            printf("%d\n",ans);
        }
    }
}

/*
5 5
GDDDS
SSDFD
SYGDS
SGGYS
SSYSS

1 4
FYGY
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值