HDU - 3681(bfs+状压dp+二分)

题目:click
题意:给定一个n*m的地图,D表示不能走的地方,G补充满能量,问从F点走完所有的Y点最小的能量,走一个消耗一格能量。
注意一下题目中所给的范围,Y+G的数量不超过15。在无数条路径中找出一条最佳路径,D是不能走的,所需点的数量顶多16个(加上了F点),其实可以发现本质就是一个TSP的变形问题,所需要的点也就这三个。bfs处理出每两个点的最短距离,建立一个新的图。
之后直接状压dp,但是我们需要注意状态的的属性问题,取最大还是最小值进行状态转移?取max有可能将最小路径的值覆盖,取min可能不能确保是这条路上的max。二分答案即可。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e7+5;
int mo[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int n,m,state,fvis;
bool vis[20][20];
int mp[20][20];
int dp[20][(1<<18)];
int cnt=0;
struct A{
    int x,y;
}a[20];
struct B{
    int x,y;
    int di;
};
int dis[20][20];
void bfs(int t1,int t2)
{
    memset(vis,false,sizeof(vis));
    queue<B>hh;
    B temp;
    temp.di=0;
    temp.x=a[t1].x;
    temp.y=a[t1].y;
    hh.push(temp);
    while(!hh.empty())
    {
        temp=hh.front();
        for(int i=0;i<4;i++)
        {
            B tmp;
            tmp.x=temp.x+mo[i][0];
            tmp.y=temp.y+mo[i][1];
            if(tmp.x<0||tmp.x>n-1||tmp.y<0||tmp.y>m-1||vis[tmp.x][tmp.y]||mp[tmp.x][tmp.y]=='D')
                continue;
            vis[tmp.x][tmp.y]=true;
            tmp.di=temp.di+1;
            if(tmp.x==a[t2].x&&tmp.y==a[t2].y)
            {
                dis[t1][t2]=tmp.di;
                dis[t2][t1]=tmp.di;
                return ;
            }
            hh.push(tmp);
        }
        hh.pop();
    }
}
bool check(int res)
{
    int i,j,k;
    int yyyy=(1<<cnt);
    memset(dp,-1,sizeof(dp));
    dp[fvis][(1<<fvis)]=res;
    for(i=0;i<yyyy;i++)
    {
        for(j=0;j<cnt;j++)
        {
            if(dp[j][i]==-1||((1<<j)&i)==0)
                continue;
            if((state&i)==state&&dp[j][i]!=-1)
                return true;
            for(k=0;k<cnt;k++)
            {
                if(dis[j][k]==inf||((1<<k)&i)||k==j)
                    continue;
                if(dp[j][i]-dis[j][k]<0)
                {
                    continue;
                }
                int temp=i|(1<<k);
                if(mp[a[k].x][a[k].y]=='G')
                {
                    dp[k][temp]=res;
                    continue;
                }
                dp[k][temp]=max(dp[k][temp],dp[j][i]-dis[j][k]);
            }
        }
    }
    return false;
}
int main()
{
    while(~scanf("%d %d",&n,&m)&&(n||m))
    {
        getchar();
        state=0;
        int i,j,k;
        cnt=0;
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
               scanf("%c",&mp[i][j]);
                if(mp[i][j]=='F'||mp[i][j]=='G'||mp[i][j]=='Y')
                {
                    if(mp[i][j]=='F')
                        fvis=cnt;
                    if(mp[i][j]=='F'||mp[i][j]=='Y')
                        state+=(1<<cnt);
                    a[cnt].x=i;
                    a[cnt++].y=j;
                    continue;
                }
            }
            getchar();
        }
        memset(dis,inf,sizeof(dis));
        for(i=0;i<cnt;i++)
        {
            for(j=0;j<cnt;j++)
            {
                if(i==j)
                    dis[i][j]=0;
                else
                    bfs(i,j);
            }
        }
        int ans=-1;
        int l=0,r=250;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(check(mid))
            {
                ans=mid;
                r=mid-1;
            }
            else
                l=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
发布了72 篇原创文章 · 获赞 19 · 访问量 7491

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/105212141
今日推荐