首页 > 其他分享 >hdu 3681(bfs+dfs+状态压缩)

hdu 3681(bfs+dfs+状态压缩)

时间:2023-05-29 19:38:11浏览次数:43  
标签:hdu 20 int 3681 head dfs next vis id


解题思路:这道题属于图上来回走的问题,可以把重复走的过程弱化,即只强调从u->v的结果,中间经过的节点都不考虑。这道题里面'G','F','Y'是重要的节点,其余的点我们是可以忽略的,也就是说,假设从u->v,我们只需要知道最短路径是多少就可以了,至于是怎么走的,中间绕过了多少个'D'都不是我们关心的。这样我们就只需要用bfs找到'G','F','Y'两两之间的最短路径,剩下的就是一个典型的TSP问题了。对于最小的电池量,可以二分答案,这里很容易想到。在dfs中,我们同样只要知道两点之间的最短路径就可以了,并不需要知道如何走过来的,此外,由于每个'Y'都必须要走到,且数据量较小,所以可以用状态压缩。

对于这种图上来回走的问题,可以把重复走的过程弱化,只强调走的结果。



#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;
}




标签:hdu,20,int,3681,head,dfs,next,vis,id
From: https://blog.51cto.com/u_16143128/6373648

相关文章

  • hdu 4012(bfs+位压缩)
    思路:每次涂色以后必有一个格子的颜色是最终的颜色,否则这次涂色根本没意义,所以我们把每次涂色后哪些格子成为最终颜色的所有可能都入队,入队的元素是一个struct包含步数和最终颜色已确定的木块集合,这个集合必须用整数表示,所以用到状态压缩,因为最多只有16个格子,所以用16位的二进制来表......
  • hdu 1593(数学)
    往相反的方面跑,但是,最理想的初始位置并不是圆点和圆上的某一点,应该还有更理想的初始逃跑状态.这里有一点需要注意,就是逃跑者极力想达到理想逃跑初态,而追赶者极力阻止逃跑者达到这一状态,所以,理想初态应该是无论追赶者如何阻止,逃跑者仍然可以达到的理想状态.最理想的......
  • hdu 3577(线段树区间更新)
    题意:输入一个t,表示有t组测试数据;         接下来一行,输入两个数,k,m,其中k表示这个辆车最多可以坐这么多人,m表示有m次询问能否上车;         每一次询问,输入两个数a,b,表示该乘客能否在a站台上车,b站台下车,乘车区间为(a,b--),先后次序;         即我每次询......
  • hdu 3172(并查集+hash)
    解题思路:典型的并查集,只是每个人的名字要转换成数字,可以用map,也可以用字典树,我最开始用的字典树结果爆内存了。。爆内存:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintmaxn=200000;intn,fa[maxn],trie[maxn][52],cnt,id[2000000],nu......
  • hdu 2795(线段树)
    解题思路:这道题很难想到是用线段树,确实转化的很巧妙实际上,我们只需要利用线段树(记录1-h)维护哪个位置的剩余空间最大即可,即1,2,......,h是线段树的叶子节点,我们每次要找的就是叶子节点的剩余空间的最大值,只要能够想到这里就很容易啦。。另外如果h>n的话,就令h=n,否则就是类似于位置多......
  • hdu 1698(线段树区间更新)
    解题思路:线段树区间更新水题。#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;constintmaxn=100005;structseg{ intl,r,sum,lazy;}tree[maxn<<2];voidbuild(intl,intr,intu){ tree[u].l=l; tree[u].r=r; t......
  • hdu 1511(dp)
    解题思路:两次dp确实很巧妙,我只想到了一次dp算出最后那个数最小,其实题目要求还要保证第一个数尽可能大,一开始也没有注意到。。AC:#include<stdio.h>#include<string.h>#include<algorithm>#include<iostream>#include<math.h>#include<stdlib.h>#include<time.h>usingnamesp......
  • poj 3411(DFS多点访问)
    题意:有n座城市和m(1<=n,m<=10)条路。现在要从城市1到城市n。有些路是要收费的,从a城市到b城市,如果之前到过c城市,那么只要付P的钱,如果没有去过就付R的钱。求的是最少要花多少钱。解题思路:这道题的n与m都很小,dfs可以搞定,但这里与以往的搜索不同,以前dfs每个节点只能够访问一次,这里有多次访......
  • hdu 5102(队列+节点扩展)
    TheK-thDistanceTimeLimit:8000/4000MS(Java/Others)    MemoryLimit:65536/65536K(Java/Others)ProblemDescriptionGivenatree,whichhasnnodeintotal.Definethedistancebetweentwonodeuandvisthenumberofedgeontheirunique......
  • hdu 5367(线段树+区间合并)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5367官方题解:对于求“高山脉”长度,可以利用线段树。树节点中保存左高度连续长度,左高度连续区间的高度,左高度连续区间的状态(即是否高于第一个高度不同的山),右高度连续长度,右高度连续区间的高度,右高度连续区间的状态,每段区间内的“......