hdu 3502 bfs+状态压缩dp

题意是给你n*m的矩阵     每个单位有一个数,-1表示不能走   》=0表示有有多少个能量能获得    问从左上角到右下角能获得的做大能量值(走一步消耗1单位能量)

思路:  先bfs求出所有线之间的最短距离(当然  有用的只有有能量值的点和起点,终点) 然后状态压缩dp  找到最大能量值    这里有几个注意的地方

状态尽量从1开始    减少数组的空间(爆了一次)   其次是bfs是只搜有能量的点     其它都差不多;

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;

#define INF 0x3f3f3f3f

int map[300][300],dis[25][25],mark[300][300],leap[300][300];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
int coord[25][3],dp[1<<18][20],n,m;
struct node
{
    int x,y;
    int step;
}a,b;
int min(int a,int b)
{
    return a<b?a:b;
}
int bfs(int k)
{
    int i;
    a.x=coord[k][1];
    a.y=coord[k][2];
    a.step=0;
    queue<node>q;
    memset(mark,0,sizeof(mark));
    mark[a.x][a.y]=1;
    q.push(a);
    while(!q.empty())
    {
        b=q.front();
        q.pop();
        for(i=0;i<4;i++)
        {
            a.x=b.x+dir[i][0];
            a.y=b.y+dir[i][1];
            a.step=b.step+1;
            if(a.x<=0||a.x>n||a.y<=0||a.y>m) continue;
            if(map[a.x][a.y]==-1) continue;
            if(mark[a.x][a.y]==0)
            {
                mark[a.x][a.y]=1;
                 dis[k][leap[a.x][a.y]]=dis[leap[a.x][a.y]][k]=a.step;
                q.push(a);
            }
        }
    }
    return 0;
}
int max(int a,int b)
{
    return a>b?a:b;
}
int main()
{
    int i,j;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
            leap[i][j]=-1;
        }
        if(map[1][1]==0&&(n>1||m>1)) {printf("you loss!\n");continue;}
        else if(n==1&&m==1) {printf("%d\n",map[1][1]);continue;}
        int t=-1;
        for(i=1;i<=n;i++)
        for(j=1;j<=m;j++)
        {
            if(map[i][j]>0)
            {
                coord[++t][1]=i;
                coord[t][2]=j;
                leap[i][j]=t;
            }
        }
        if(map[n][m]==0)
        {
            coord[++t][1]=n;
            coord[t][2]=m;
            leap[n][m]=t;
        }
        memset(dis,INF,sizeof(dis));
        for(i=0;i<t;i++)
        {
            dis[i][i]=0;
            bfs(i);
        }
        dis[t][t]=0;
        memset(dp,-1,sizeof(dp));
        dp[1][0]=map[1][1];
        int k=(1<<(t+1));
        int Max=-1;
        for(i=1;i<k;i++)
        {
            for(j=0;j<=t;j++)
            {
                if((i&(1<<j))==0) continue;
                if(dp[i][j]<0) continue;//开始少了这句超时了一次
                for(int x=0;x<=t;x++)
                {
                    if(x==j) continue;
                    if(dp[i][j]<dis[j][x]) continue;
                    if((i&(1<<x))!=0) continue;
                    dp[i|(1<<x)][x]=max(dp[i|(1<<x)][x],dp[i][j]-dis[x][j]+map[coord[x][1]][coord[x][2]]);
                    Max=max(Max,dp[i|(1<<x)][x]-dis[x][t]);
                    //printf("^^^  %d\n",Max);
                }
            }
        }
        if(Max<0) printf("you loss!\n");
        else printf("%d\n",Max);
    }
    return 0;
}
时间: 2024-12-22 06:48:57

hdu 3502 bfs+状态压缩dp的相关文章

HDU 3247 Resource Archiver (AC自己主动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串.m个病毒串,问包括全部正常串(可重叠)且不包括不论什么病毒串的字符串的最小长度为多少. AC自己主动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.能够优化非常多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> us

HDU 3247 Resource Archiver (AC自动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串,m个病毒串,问包含所有正常串(可重叠)且不包含任何病毒串的字符串的最小长度为多少. AC自动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.可以优化很多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> using n

hdu 4568(状态压缩dp)

题意:一张n*m的网格内每个点有话费,还有若干个宝藏,问一个人要走进去拿走所有宝藏在走出来的最小花费. 思路:看宝藏只有13个直接想到了状压dp[i][j]拿了哪几个前一个为j的最小花费,先bfs+优先队列预处理出最短路,然后记忆化搜索就可. 代码如下: 1 /************************************************** 2 * Author : xiaohao Z 3 * Blog : http://www.cnblogs.com/shu-xiaohao

hdu 3681 二分+状态压缩dp+bfs

题意就不用多说了,开始想直接bfs+二分简化下做试试   果断超时,然后不得不用状态压缩dp(其实一开始就想这样做的,15个点   每个点都能走多次   绝逼状态压缩dp) 先bfs跑每个关键点之间的做短路径    再二分起点的能量值               状态压缩dp来判断     不说了    AC吧!!!!! #include<stdio.h> #include<string.h> #include<queue> #include<iostream&g

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

HDU 3247 Resource Archiver AC自动机 + bfs + 状态压缩dp

题意:给定你n个文本串 ,m个模式串,怎么构造最短的新的文本串使得这个新的文本串包含n个文本串的所有信息且文本串的长度最短且不包含模式串. 解题思路:这里看题解撸的,首先我们算出两两文本串的距离(end数组标记文本和模式串的值不同,利用这个进行bfs算出两两之间的最短距离,注意到这里模式串的end是不能走到的.这里也不需要松弛操作),然后因为n只有10这么大,所以我们可以状态压缩  ,dp[i][j] 表示 压缩后状态为 i(二进制压缩,每i位表示第i个是否在)且 以j结尾的文本串的最小花费.这

HDU 3001 Travelling 状态压缩dp+3进制

题意:一个人要旅行,他要去n个地方,且这n个地方每个地方最多可以走2次: 给m条路径,寻问最短花费 很明显的状态压缩,但是要求每个点最多只能走两次,就没办法标记当前点走过或是没走过,只能用三进制来表示 1代表地点1被走过一次. 2代表地点1被走过两次. 3(即10)代表地点2被走过一次. 4(即11)代表地点1被走过一次,地点2被走过一次. 5(即12)代表地点1被走过两次,地点2被走过一次. 附AC代码 #include<stdio.h> #include<string.h> i

HDU 4628 Pieces(状态压缩DP)

题目链接:传送门 题意: 给定一个长度小于16的字符串然后每次可以去掉它的一个回文子序列,问最少删除多少次可以使这个字符串为空. 分析: 首先预处理出这个字符串的所有回文子序列,然后将其压缩成二进制x,然后dp[x]表示这个序列删除所需要的最小的步数,然后dp[x] = min(dp[x],dp[sub])sub表示x的所有子序列. 代码如下: #include <iostream> #include <string> #include <cstring> #inclu

hdu 1429(BFS+状态压缩)

胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7895    Accepted Submission(s): 2795 Problem Description Ignatius再次被魔王抓走了(搞不懂他咋这么讨魔王喜欢)…… 这 次魔王汲取了上次的教训,把Ignatius关在一个n*m的地牢里,并在地牢的某些地方安装了