hdu 3681 Prison Break (状态压缩dp/dfs + bfs)

30 篇文章 0 订阅

题意:一幅矩阵迷宫,給起点,开始时充满电,要求是遍历给定的点,每移动一次花费1,

迷宫中有若干充电池可充满电(每个充电池只能用一次),求原始电量最少是多少。


分析:

1、由于所有'Y'处一定要走到,‘G'可以走也可以不走,且他们的总个数最多只有15个。

the sum of energy pools and power switches is less than 15.

因此可以用状态压缩思想记录最终的状态。

因此要给这些符号所在的位置编号。 用hash思想把图中各符号的位置用横纵坐标唯一表示。

即posid=x*列数+y。

2、重新建图,把能走的点之间建边,然后bfs出图中任意两个点之间的最短距离。

3、二分枚举原始电量,找到最小值。

验证能否达到末态的过程中,如果要走的点为'G',则电量为原始的满电量,否则为这一步的起点

位置电量 - 起点到终点的最短距离。


bfs+dfs

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>

using namespace std;

struct edge
{
    int to,next;
}e[2000];

struct node
{
    int vid,step;
};

char mp[20][20];
int id[20][20],c[20][2],head[300],dis[20][20];
int cnt,obj,ids,mid,m,n;
bool mk[20];

void init()
{
    memset(id,-1,sizeof(id));
    memset(dis,-1,sizeof(dis));
    memset(head,-1,sizeof(head));
    cnt=0;ids=1;obj=0;
}

void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}

void bfs(int x)
{
    int u,v;
    node djw,cur,next;
    queue<node> q;
    bool vis[400];
    memset(vis,0,sizeof(vis));

    djw.vid=x;
    djw.step=0;
    q.push(djw);
    vis[x]=true;
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        u=cur.vid;
        if(id[u/m][u%m]!=-1)
            dis[id[x/m][x%m]][id[u/m][u%m]]=cur.step;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            v=e[i].to;
            if(!vis[v])
            {
                vis[v]=true;
                next.vid=v;
                next.step=cur.step+1;
                q.push(next);
            }
        }
    }
}

int dfs(int bag,int pos,int sta)
{
    if((sta&obj)==obj) return 1;
    for(int i=0;i<ids;i++)
    {
        if(mk[i] || dis[pos][i]==-1) continue;
        if(dis[pos][i]<=bag)
        {
            if(mp[c[i][0]][c[i][1]]=='G')
            {
                mk[i]=true;
                if(dfs(mid,i,sta|(1<<i))) return 1;
                mk[i]=false;
            }
            else
            {
                mk[i]=true;
                if(dfs(bag-dis[pos][i],i,sta|(1<<i))) return 1;
                mk[i]=false;
            }
        }
    }
    return 0;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0 && m==0)
            break;
        init();
        for(int i=0;i<n;i++)
            scanf("%s",mp[i]);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='D') continue;
                if(mp[i][j]=='F')
                {
                    c[0][0]=i;
                    c[0][1]=j;
                    id[i][j]=0;
                }
                else if(mp[i][j]=='G')
                {
                    c[ids][0]=i;
                    c[ids][1]=j;
                    id[i][j]=ids++;
                }
                else if(mp[i][j]=='Y')
                {
                    c[ids][0]=i;
                    c[ids][1]=j;
                    obj|=(1<<ids);
                    id[i][j]=ids++;
                }
                if(i-1>=0 && mp[i-1][j]!='D')
                    add(i*m+j,(i-1)*m+j);
                if(i+1<n && mp[i+1][j]!='D')
                    add(i*m+j,(i+1)*m+j);
                if(j-1>=0 && mp[i][j-1]!='D')
                    add(i*m+j,i*m+j-1);
                if(j+1<m && mp[i][j+1]!='D')
                    add(i*m+j,i*m+j+1);
            }
        }
        for(int i=0;i<ids;i++)
            bfs(c[i][0]*m+c[i][1]);
        int flag=1;
        for(int i=1;i<ids;i++)
        {
            if(mp[c[i][0]][c[i][1]]=='Y' && dis[0][i]==-1)
            {
                flag=0;
                break;
            }
        }
        int ans=-1;
        if(flag)
        {
            int l=0,r=n*m*(ids-1);
            while(l<=r)
            {
                mid=(l+r)>>1;
                memset(mk,0,sizeof(mk));
                mk[0]=true;
                if(dfs(mid,0,1))
                {
                    ans=mid;
                    r=mid-1;
                }
                else
                    l=mid+1;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


dp+bfs

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>

using namespace std;

struct edge
{
    int to,next;
}e[2000];

struct node
{
    int vid,step;
};

char mp[20][20];
int id[20][20],c[20][2],head[300],dis[20][20];
int dp[1<<16][16];
int cnt,obj,ids,mid,m,n;

void init()
{
    memset(id,-1,sizeof(id));
    memset(dis,-1,sizeof(dis));
    memset(head,-1,sizeof(head));
    cnt=0;ids=1;obj=0;
}

void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}

void bfs(int x)
{
    int u,v;
    node djw,cur,next;
    queue<node> q;
    bool vis[400];
    memset(vis,0,sizeof(vis));

    djw.vid=x;
    djw.step=0;
    q.push(djw);
    vis[x]=true;
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        u=cur.vid;
        if(id[u/m][u%m]!=-1)
            dis[id[x/m][x%m]][id[u/m][u%m]]=cur.step;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            v=e[i].to;
            if(!vis[v])
            {
                vis[v]=true;
                next.vid=v;
                next.step=cur.step+1;
                q.push(next);
            }
        }
    }
}

int solve(int mid)
{
    memset(dp,-1,sizeof(dp));
    dp[1][0]=mid;
    for(int i=0;i<(1<<ids);i++)
    {
        for(int j=0;j<ids;j++)
        {
            if((i&(1<<j)==0) || dp[i][j]==-1) continue;
            if((i&obj)==obj) return 1;
            for(int k=0;k<ids;k++)
            {
                if(j==k || i&(1<<k)) continue;
                if(dis[j][k]==-1) continue;
                if(dp[i][j]>=dis[j][k])
                {
                    if(dp[i|(1<<k)][k]==-1 || dp[i|(1<<k)][k]<dp[i][j]-dis[j][k])
                        dp[i|(1<<k)][k]=dp[i][j]-dis[j][k];
                    if(mp[c[k][0]][c[k][1]]=='G')
                        dp[i|(1<<k)][k]=mid;
                }
            }
        }
    }
    return 0;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0 && m==0)
            break;
        init();
        for(int i=0;i<n;i++)
            scanf("%s",mp[i]);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='D') continue;
                if(mp[i][j]=='F')
                {
                    c[0][0]=i;
                    c[0][1]=j;
                    id[i][j]=0;
                }
                else if(mp[i][j]=='G')
                {
                    c[ids][0]=i;
                    c[ids][1]=j;
                    id[i][j]=ids++;
                }
                else if(mp[i][j]=='Y')
                {
                    c[ids][0]=i;
                    c[ids][1]=j;
                    id[i][j]=ids++;
                    obj|=(1<<(ids-1));
                }
                if(i-1>=0 && mp[i-1][j]!='D')
                    add(i*m+j,(i-1)*m+j);
                if(i+1<n && mp[i+1][j]!='D')
                    add(i*m+j,(i+1)*m+j);
                if(j-1>=0 && mp[i][j-1]!='D')
                    add(i*m+j,i*m+j-1);
                if(j+1<m && mp[i][j+1]!='D')
                    add(i*m+j,i*m+j+1);
            }
        }
        for(int i=0;i<ids;i++)
            bfs(c[i][0]*m+c[i][1]);
        int ans=-1;
        int l=0,r=n*m*(ids-1);
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(solve(mid))
            {
                ans=mid;
                r=mid-1;
            }
            else
                l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值