HDU 3681 BFS&状压DP&二分

N*M矩阵,从F点出发,走完所有的Y点,每走一格花费1点电量,走到G点时,电量充满,D不可到达,问起始时的最小满电量可以走完所有Y,Y和G一共最多15个

先BFS出所有的F,Y,G之间的最短距离。

然后二分起始电量,对每个电量,做状压DP判断是否可行

#include "stdio.h"
#include "string.h"
#include "queue"
using namespace std;

int inf=0x3f3f3f3f;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node
{
    int x,y,step;
};
struct Mark
{
    int x,y;
}mark[21];

char map[21][21];
int step[21][21],b[21],dp[70010][21],dis[21][21];
int cnt,aim,start,n,m;

int Min(int a,int b)
{
    if (a<b) return a;else return b;
}
void bfs(int x,int y)
{
    queue<node>q;
    node cur,next;
    int i;

    memset(step,inf,sizeof(step));
    step[x][y]=0;
    cur.x=x;
    cur.y=y;
    cur.step=0;
    q.push(cur);
    while (!q.empty())
    {
        cur=q.front();
        q.pop();
        for (i=0;i<4;i++)
        {
            next.x=cur.x+dir[i][0];
            next.y=cur.y+dir[i][1];
            if (next.x<0 || next.x>=n || next.y<0 || next.y>=m) continue;
            if (map[next.x][next.y]=='D') continue;
            if (step[next.x][next.y]!=inf) continue;

            next.step=cur.step+1;
            step[next.x][next.y]=next.step;
            q.push(next);
        }
    }
}

int DP(int key)
{
    int i,j,k;
    memset(dp,inf,sizeof(dp));

    dp[b[start]][start]=0;

    for (i=0;i<b[cnt];i++)
        for (j=0;j<cnt;j++)
            if ((b[j]&i)==b[j] && dp[i][j]!=inf)
            {
                for (k=0;k<cnt;k++)
                    if (k!=j && (b[k]&i)!=b[k] && dp[i][j]+dis[j][k]<=key)
                    {
                        dp[i+b[k]][k]=Min(dp[i+b[k]][k],dp[i][j]+dis[j][k]);
                        if (map[mark[k].x][mark[k].y]=='G') dp[i+b[k]][k]=0;
                        if (((i+b[k])&aim)==aim) return 1;
                    }
            }
    return 0;

}
int main()
{
    int i,j,l,r,mid,ans;
    b[0]=1;
    for (i=1;i<=16;i++)
        b[i]=b[i-1]*2;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        if (n==0 && m==0) break;
        cnt=0;
        getchar();
        for (i=0;i<n;i++)
            gets(map[i]);

        aim=0;
        for (i=0;i<n;i++)
            for (j=0;j<m;j++)
                if (map[i][j]=='F' || map[i][j]=='Y' || map[i][j]=='G')
                {
                    if (map[i][j]!='G') aim+=b[cnt];
                    if (map[i][j]=='F') start=cnt;
                    mark[cnt].x=i;
                    mark[cnt].y=j;
                    cnt++;
                }

        memset(dis,inf,sizeof(dis));
        for (i=0;i<cnt;i++) // BFS出,F,Y,G之间的最短距离
        {
            bfs(mark[i].x,mark[i].y);
            for (j=0;j<cnt;j++)
                dis[i][j]=step[mark[j].x][mark[j].y];
        }

        l=0; r=n*m;
        ans=-1;
        while (l<=r) // 二分电量
        {
            mid=(l+r)/2;

            if (DP(mid)==1)
            {
                ans=mid;
                r=mid-1;
            }
            else
                l=mid+1;
        }
        printf("%d\n",ans);

    }
    return 0;
}
时间: 2025-01-15 05:14:10

HDU 3681 BFS&状压DP&二分的相关文章

HDU-3681-Prison Break(BFS+状压DP+二分)

Problem Description Rompire is a robot kingdom and a lot of robots live there peacefully. But one day, the king of Rompire was captured by human beings. His thinking circuit was changed by human and thus became a tyrant. All those who are against him

hdu 4568 bfs + 状压dp

//这题的数据是不是有问题... 不考虑宝藏一个也拿不到也能AC... 1 #include "bits/stdc++.h" 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 int T; 5 int N, M; 6 int mat[210][210]; 7 int K; 8 int tot_tra, tra[210][210]; 9 10 //dp parameters 11 int dis_tra_broder[20],

HDU 4856 Tunnels(BFS+状压DP)

HDU 4856 Tunnels 题目链接 题意:给定一些管道,然后管道之间走是不用时间的,陆地上有障碍,陆地上走一步花费时间1,求遍历所有管道需要的最短时间,每个管道只能走一次 思路:先BFS预处理出两两管道的距离,然后状态压缩DP求解,dp[s][i]表示状态s,停在管道i时候的最小花费 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using

HDU 4284Travel(状压DP)

HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1走完所有的他必须要去的城市,打完所有的工,并且成功回到起点1 由于H<=15,所以显然可以状压,预处理这些都必须去的城市之间的最短距离(可以floyd),然后状压DP[S][i]表示他到达了S这些城市后正处在第i个城市里(所以S & (1<<i) != 0)的剩余的最大的钱的数量,然

HDU-3502-Huson&#39;s Adventure Island(BFS+状压DP)

Problem Description A few days ago, Tom was tired of all the PC-games, so he went back to some old FC-games. "Hudson's Adventure Island" was his favorite which he had played thousands of times. But to his disappointed, the more he played, the mo

HDU 3001 Travelling 状压DP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意:还是环游地图的问题,只不过这回旅行者对自己有着严格的要求,地图上每个点的经过次数不能超过两次. 思路:依然是状压DP问题,根上一道很像,只不过这次对于每个点来说有三种状态,分别是未经过,经过一次,经过两次.所以要用三进制的数来进行状态压缩,这个关键点想明白了其他的和上一道基本一样了.对于我来说需要注意的是:能够到达某一个点经过了两次的状态的前一个状态是这个点已经经过了一次的状态,而不是从来未

HDU-4856 Tunnels (BFS+状压DP)

Problem Description Bob is travelling in Xi’an. He finds many secret tunnels beneath the city. In his eyes, the city is a grid. He can’t enter a grid with a barrier. In one minute, he can move into an adjacent grid with no barrier. Bob is full of cur

POJ 2688 BFS+状压DP

标准的TSP问题 m*n矩阵,有不超过10个需要走到的点,给出起点,问走最少的步子把所有点走完 BFS出每个必须走到的点的最短距离 然后状压DP即可 #include "stdio.h" #include "string.h" #include "queue" using namespace std; const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} }; int inf=0x7fffffff; in

[luoguP3092] [USACO13NOV]没有找零No Change(状压DP + 二分)

传送门 先通过二分预处理出来,每个硬币在每个商品处最多能往后买多少个商品 直接状压DP即可 f[i]就为,所有比状态i少一个硬币j的状态所能达到的最远距离,在加上硬币j在当前位置所能达到的距离,所有的取max 是满足最优解性质的 #include <cstdio> #include <iostream> #include <algorithm> #define N 17 #define max(x, y) ((x) > (y) ? (x) : (y)) int n