菜鸟系列——简单搜索

菜鸟就要老老实实重新学起:

简单搜索:

一些简单搜索题,其中一些源自kuangbin大神的题目列表,留下以后出题用。

eg:

POJ1321 棋盘问题

http://poj.org/problem?id=1321

题意:
在一个棋盘内放k个棋子,每一行每一列都最多只能有一个棋子,求方法数,‘#’为可放的地方。
思路:
直接暴力深搜枚举所有情况即可,每一行选择一个点向下继续深搜,同时a[]储存该列是否已有棋子。
code:
#define N 11

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int a[N];
int g[N][N];
char s[101];
void dfs(int now,int step)
{
    if(step==m)
    {
        sum++;
        return;
    }
    if(now==n)
        return;
    for(int i=0;i<n;i++)
        if(g[now][i]&&!a[i])
        {
            a[i]=1;
            dfs(now+1,step+1);
            a[i]=0;
        }
    dfs(now+1,step);
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF&&n!=-1)
    {
        memset(g,0,sizeof(g));
        memset(a,0,sizeof(a));
        for(i=0;i<n;i++)
        {
            scanf("%s",s);
            x=strlen(s);
            for(j=0;j<x;j++)
                if(s[j]=='#')
                    g[i][j]=1;
        }
        sum=0;
        dfs(0,0);
        printf("%d\n",sum);
    }
    return 0;
}

POJ2251 Dungeon Master

http://poj.org/problem?id=2251

题意:
三维空间,求从S点到E点的最小距离。
思路:
简单bfs搜索,从起点开始压入队列逐渐广搜开直到找到E或者队列为空,注意标记走过的位置。
code:
#define N 112

int n,m,r,xx,yy,zz;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N][N];
int dir[6][3]={1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1};
char s[N];
struct node
{
    int x,y,z,step;
}tn;
int bfs(int x,int y,int z)
{
    queue<node> q;
    while(!q.empty())q.pop();
    node a,b;
    a.x=x;a.y=y;a.z=z;a.step=0;
    q.push(a);
    while(!q.empty())
    {
        a=q.front();q.pop();
        if(a.x==xx&&a.y==yy&&a.z==zz)
            return a.step;
        for(int i=0;i<6;i++)
        {
            b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.z=a.z+dir[i][2];
            if(b.x>=n||b.x<0||b.y>=m||b.y<0||b.z>=r||b.z<0)
                continue;
            if(g[b.z][b.x][b.y])
            {
                g[b.z][b.x][b.y]=0;
                b.step=a.step+1;
                q.push(b);
            }
        }
    }
    return -1;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d%d",&r,&n,&m)!=EOF&&n)
    {
        memset(g,0,sizeof(g));
        for(k=0;k<r;k++)
            for(i=0;i<n;i++)
            {
                scanf("%s",s);
                int len=strlen(s);
                for(j=0;j<len;j++)
                {
                    if(s[j]=='#')
                        continue;
                    g[k][i][j]=1;
                    if(s[j]=='S')
                        x=i,y=j,z=k;
                    if(s[j]=='E')
                        xx=i,yy=j,zz=k;
                }
            }
        t=bfs(x,y,z);
        if(t==-1)
            printf("Trapped!\n");
        else
            printf("Escaped in %d minute(s).\n",t);
    }
    return 0;
}

POJ3278 Catch That Cow

http://poj.org/problem?id=3278

题意:
求从第一个数变换到第二个数的最小步骤,数字每一步都可以加减1或者扩大2倍。
思路:
暴力bfs搜索,状态有加一、减一、乘二,三种。
code:
#define N 212345

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
    int x,y;
}tn;
int main()
{
    queue<node> q;
    node g,h;
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        while(!q.empty())q.pop();
        memset(vis,false,sizeof(vis));
        g.x=n;g.y=0;vis[n]=true;
        res=INF;
        q.push(g);
        while(res==INF&&!q.empty())
        {
            g=q.front();q.pop();
            if(g.x==m)res=g.y;
            h.x=g.x+1;h.y=g.y+1;
            if(h.x<N&&!vis[h.x])
                vis[h.x]=true,q.push(h);
            h.x=g.x-1;
            if(h.x>=0&&!vis[h.x])
                vis[h.x]=true,q.push(h);
            h.x=g.x*2;
            if(h.x<N&&!vis[h.x])
                vis[h.x]=true,q.push(h);
        }
        printf("%d\n",res);
    }
    return 0;
}

POJ3279 Fliptile

http://poj.org/problem?id=3279

题意:
给出一些板子的正反状态,一头牛踩这些板子,每次踩下去之后被踩的板子和周围的四个都会翻转,求一种踩板子的方式能够使得所有板子都‘0’朝上。
思路:

暴力枚举第一行的所有可能方案,之后向下搜索得出该方案是否可行。

因为每次变换的都是一个十字形区域,所以枚举得出第一行的状态后,可以得出当前第一行每个板子的状态,由此可以决定第二行对应板子的状态,由此不断向下搜索直到最后一行时判断是否都为0。第一行的枚举可以用状态压缩。

code:
#define N 20

int n,m;
int flag,sum,ave,res,len,ans1,ans2;
int f[N][N];
int ans[N][N];
int g[N][N];
bool mark(int x,int y)
{
    return f[x-1][y]^f[x+1][y]^f[x][y-1]^f[x][y+1]^f[x][y]^g[x][y];
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(g,0,sizeof(g));
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                scanf("%d",&g[i][j]);
        for(k=0;k<(1<<m);k++)
        {
            memset(f,0,sizeof(f));
            for(i=1;i<=m;i++)
                f[1][i]=k&(1<<(i-1))?1:0;
            for(i=1;i<n;i++)
                for(j=1;j<=m;j++)
                        f[i+1][j]=mark(i,j)?1:0;
            flag=1;
            for(i=1;i<=m;i++)
                if(mark(n,i))
                    flag=0;
            if(flag)
                break;
        }
        if(!flag)
        {
            printf("IMPOSSIBLE\n");
            continue;
        }
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=m;j++)
                printf("%d ",f[i][j]);
            printf("\n");
        }
    }
    return 0;
}

POJ1426 Find The Multiple

http://poj.org/problem?id=1426

题意:
寻找一个只包含1和0的十进制数是n的倍数。
思路:
因为这个倍数的每一位都只有1或0两种状态,所以可以从首位开始向后bfs每种状态展开成末尾加1或0两种状态,直到得出结果。
code:
#define N 1123

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
    int now;
    string s;
}tn;
int main()
{
    int i,j,k,kk,t,x,y,z;
    queue<node> q;
    node a,b,c;
    while(scanf("%d",&n)!=EOF&&n)
    {
        while(!q.empty())q.pop();
        memset(vis,false,sizeof(vis));
        a.now=1;a.s="1";vis[1]=true;
        q.push(a);
        while(!q.empty())
        {
            a=q.front();q.pop();
            b.s=a.s+"1";c.s=a.s+"0";
            b.now=(a.now*10+1)%n;c.now=(a.now*10)%n;
            if(!b.now)
            {
                cout<<b.s<<endl;
                break;
            }
            if(!c.now)
            {
                cout<<c.s<<endl;
                break;
            }
            if(!vis[b.now])
            {
                vis[b.now]=true;
                q.push(b);
            }
            if(!vis[c.now])
            {
                vis[c.now]=true;
                q.push(c);
            }
        }
    }
    return 0;
}

POJ3126 Prime Path

http://poj.org/problem?id=3126

题意:
要求从第一个四位数变成第二个四位数字,每次只能改变某一位的数字,且每次改变之后的四位数必须是质数,求最少变换步骤,
思路:
只有四位数而且求最少,直接暴力BFS,筛素数打表出四位数的所有素数判断,之后从第一个数字开始bfs,每次展开成4种状态,改变其中一位,同时判断是否为素数,直到得出结果。
code:
#define N 11234

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
struct node
{
    int x,y,z;
}tn;
bool mark[N];
int pri[N],cnt;
void SP()
{
    cnt=0;
    memset(mark,true,sizeof(mark));
    mark[0]=mark[1]=false;
    for(int i=2;i<N;i++)
    {
        if(mark[i])
            pri[cnt++]=i;
        for (int j=0;(j<cnt)&&(i*pri[j]<N);j++)
        {
            mark[i*pri[j]]=false;
            if (i%pri[j]==0)
                break;
        }
    }
}
int main()
{
    int i,j,k,kk,t,x,y,z,w,now;
    SP();
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d %d",&n,&m);
        memset(vis,false,sizeof(vis));
        queue<node> q;
        while(!q.empty())q.pop();
        node g,h;
        g.x=n;g.y=0;
        q.push(g);
        flag=0;
        vis[n]=true;
        while(!q.empty())
        {
            g=q.front();q.pop();
            if(g.x==m)
            {
                flag=1;
                res=g.y;
                break;
            }
            x=g.x/1000;y=g.x/100%10;z=g.x/10%10;w=g.x%10;
            t=g.x-x*1000;
            for(i=1;i<=9;i++)
            {
                now=t+i*1000;
                if(now!=g.x&&!vis[now]&&mark[now])
                {
                    vis[now]=true;
                    h.x=now;h.y=g.y+1;h.z=g.x;
                    q.push(h);
                }
            }
            t=g.x-y*100;
            for(i=0;i<=9;i++)
            {
                now=t+i*100;
                if(now!=g.x&&!vis[now]&&mark[now])
                {
                    vis[now]=true;
                    h.x=now;h.y=g.y+1;h.z=g.x;
                    q.push(h);
                }
            }
            t=g.x-z*10;
            for(i=0;i<=9;i++)
            {
                now=t+i*10;
                if(now!=g.x&&!vis[now]&&mark[now])
                {
                    vis[now]=true;
                    h.x=now;h.y=g.y+1;h.z=g.x;
                    q.push(h);
                }
            }
            t=g.x-w;
            for(i=0;i<=9;i++)
            {
                now=t+i;
                if(now!=g.x&&!vis[now]&&mark[now])
                {
                    vis[now]=true;
                    h.x=now;h.y=g.y+1;h.z=g.x;
                    q.push(h);
                }
            }
        }
        if(flag)
            printf("%d\n",res);
        else
            printf("Impossible\n");
    }
    return 0;
}

POJ3087 Shuffle'm Up

http://poj.org/problem?id=3087

题意:
有两摞牌,现在要求通过特定的洗牌方式得到要求的序列,洗牌时只能将两摞牌交叉在一起,第一摞的第一张在最上面,然后上面一半为新的第一裸,下面一半为新的后一半,求洗出要求序列的次数。
思路:
其实是简单模拟题,那为什么在搜索题列表里,,,其实我也不知道什么情况(逃···

就是模拟洗牌就行了,只要记录每次的序列,出现相同序列则无解,map或者set或者hash或者手写字典树等等,方法很多啦,

code:
#define N 512

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int main()
{
    int i,j,k,kk,t,x,y,z;
    #ifndef ONLINE_JUDGE
        freopen("test.txt","r",stdin);
    #endif
    map<string,bool> mp;
    string s,ss,s1,s2;
    cin>>k;
    kk=0;
    while(k--)
    {
        mp.clear();
        scanf("%d",&n);
        cin>>s1>>s2>>ss;
        s=ss;
        mp[ss]=true;
        sum=0;
        while(1)
        {
            sum++;
            for(j=0,i=0;i<n;i++)
                s[j++]=s2[i],s[j++]=s1[i];
            if(s==ss)
            {
                printf("%d %d\n",++kk,sum);
                break;
            }
            if(mp[s])
            {
                printf("%d -1\n",++kk);
                break;
            }
            mp[s]=true;
            s1.assign(s,0,n);s2.assign(s,n,n);
        }
    }
    return 0;
}

FZU2150 Fire Game

http://poj.org/problem?id=3984http://acm.fzu.edu.cn/problem.php?pid=2150

题意:
两个熊孩子防火烧草堆,#代表草堆,点燃的草堆会在下一秒点燃周围上下左右的其他草堆,求所有草堆被烧完的最少时间,两个熊孩子不能烧完所有草堆输出-1.
思路:
所有草堆分块,超过2个块则不能烧完,一开始想错,用了两次BFS第一次找到每个块最远的那个点,然后bfs从那个点扫回来找到最长路径,从而求出烧这些草堆的最小时间,但是当只有一块草堆时,两个起点并不确定,一开始以为直接把最长路分4段从中间两点开始就行,但是最长路外的次长路并不一定多长,所以这种解法错误。

那么就只能暴力枚举所有的两个点的组合,bfs求出这两个点开始烧的时间,每一次都bfs依然会超时,可以提前以每一个点为起点bfs一次,确定当前起点时其他点被烧到的时间,然后枚举两点,直接得出所有其他点被烧到时间为这两点烧过去的最小值。

这题要敢于暴力枚举所有的两点组合,并且扫所有点,也就是有6层循环,同注意记录。

code:
#define N 15

int n,m;
int flag,sum,ave,ans,len,ans1,ans2;
int g[N][N];
int res[N][N][N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[101];
struct node
{
    int x,y;
    int now;
}tn;
void bfs(int x,int y,int xx,int yy)
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    memset(vis,false,sizeof(vis));
    a.x=xx;a.y=yy;a.now=0;
    res[x][y][xx][yy]=0;
    q.push(a);
    vis[xx][yy]=true;
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x+=dir[i][0];b.y+=dir[i][1];
            if(g[b.x][b.y]&&!vis[b.x][b.y])
            {
                vis[b.x][b.y]=true;
                b.now=a.now+1;
                res[x][y][b.x][b.y]=b.now;
                q.push(b);
            }
        }
    }
}
int main()
{
    int i,j,k,kk,t,x,xx,y,yy,z;
    scanf("%d",&k);
    kk=0;
    while(k--)
    {
        scanf("%d%d",&n,&m);
        memset(g,0,sizeof(g));
        for(i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(j=1;j<=m;j++)
                if(s[j-1]=='#')
                    g[i][j]=1,ave++;
        }
        memset(res,0x3f,sizeof(res));
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(g[i][j])
                    bfs(i,j,i,j);
        sum=INF;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(g[i][j])
                    for(int ii=1;ii<=n;ii++)
                        for(int jj=1;jj<=m;jj++)
                            if(g[i][j]&&g[ii][jj])
                            {
                                ans=0;
                                for(int iii=1;iii<=n;iii++)
                                    for(int jjj=1;jjj<=m;jjj++)
                                        if(g[iii][jjj])
                                            ans=max(ans,min(res[i][j][iii][jjj],res[ii][jj][iii][jjj]));
                                sum=min(sum,ans);
                            }
        printf("Case %d: ",++kk);
        if(sum==INF)
            printf("-1\n");
        else
            printf("%d\n",sum);
    }
    return 0;
}

POJ3414 Pots

http://poj.org/problem?id=3414

题意:
有两个已知容量的杯子,要通过他们倒出c升水。
思路:
常见的智力题,编程实现,每次只有6种情况,倒满1、倒满2、倒掉1,倒掉2,1倒给2,2倒给1,所以直接暴力bfs找结果就行了,代码有点挫,状态少习惯直接全写出来了,没错我就是懒的写个循环,,,
code:
#define N 112345

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2,cnt;
bool vis[N];
char s[1000];
struct node
{
    int now,x,y;
    vector<int> s;
}tn;
node bfs()
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b; int t;
    a.x=0;a.y=0;
    a.now=0;a.s.clear();
    vis[0]=true;
    q.push(a);
    while(!q.empty())
    {
        a=q.front();q.pop();
        if(a.x==res||a.y==res)
            return a;
        b=a;
        b.x=n;b.now++;b.s.push_back(1);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
        b=a;
        b.y=m;b.now++;b.s.push_back(2);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
        b=a;
        b.x=0;b.now++;b.s.push_back(3);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
        b=a;
        b.y=0;b.now++;b.s.push_back(4);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
        b=a;
        t=min(b.x+b.y,m);b.x=max(b.x+b.y-m,0);b.y=t;
        b.now++;b.s.push_back(5);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
        b=a;
        t=min(b.x+b.y,n);b.y=max(b.x+b.y-n,0);b.x=t;
        b.now++;b.s.push_back(6);
        if(!vis[b.x*1000+b.y]){vis[b.x*1000+b.y]=true;q.push(b);}
    }
    a.now=-1;
    return a;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d%d",&n,&m,&res)!=EOF&&n)
    {
        memset(vis,false,sizeof(vis));
        tn=bfs();
        if(tn.now==-1)
            printf("impossible\n");
        else
        {
            printf("%d\n",tn.now);
            for(i=0;i<tn.now;i++)
            {
                if(tn.s[i]==1)
                    printf("FILL(1)\n");
                if(tn.s[i]==2)
                    printf("FILL(2)\n");
                if(tn.s[i]==3)
                    printf("DROP(1)\n");
                if(tn.s[i]==4)
                    printf("DROP(2)\n");
                if(tn.s[i]==5)
                    printf("POUR(1,2)\n");
                if(tn.s[i]==6)
                    printf("POUR(2,1)\n");
            }
        }
    }
    return 0;
}


POJ3984 迷宫问题

http://poj.org/problem?id=3984
题意:
给出一个5*5的0/1阵,0为可走,求从左上角到右下角的最短路径,
思路:
BFS入门,可以回溯记录路径,但是为了方便直接写结构体里了。
code:

#define N 15

int n,m;
int flag,sum,ave,ans,len,ans1,ans2;
#define N 11

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
struct node
{
    int x,y,now;
    vector<int> s;
}tn;
node bfs(int x,int y)
{
    queue<node> q;
    while(!q.empty())q.pop();
    node a,b;
    a.x=x;a.y=y;a.now=1;a.s.clear();a.s.push_back(0);
    q.push(a);
    vis[x][y]=true;
    while(!q.empty())
    {
        a=q.front();q.pop();
        if(a.x==5&&a.y==5)
            return a;
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x+=dir[i][0];b.y+=dir[i][1];
            if(!vis[b.x][b.y]&&g[b.x][b.y])
            {
                vis[b.x][b.y]=true;
                b.now=a.now+1;b.s.push_back((b.x-1)*10+(b.y-1));
                q.push(b);
            }
        }
    }
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    memset(g,0,sizeof(0));
    for(i=1;i<=5;i++)
        for(j=1;j<=5;j++)
        {
            scanf("%d",&t);
            g[i][j]=t?0:1;
        }
    memset(vis,false,sizeof(vis));
    tn=bfs(1,1);
    for(i=0;i<tn.now;i++)
        printf("(%d, %d)\n",tn.s[i]/10,tn.s[i]%10);
    return 0;
}

UVA11624 Fire!

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2671
题意:
着火了,J要跑出这个房间,#是墙,F是火,火每秒点着周围的格子,求J跑出房间的最短时间。
思路:
bfs两次,先将所有火的位置入队列,求出所有位置被火烧到的最短时间,然后bfsJ的所有逃跑路线找到在火烧到前的一条路线即可。
code:
#define N 1123

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int xx[N],yy[N];
int f[N][N];
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[101];
struct node
{
    int x,y;
    int now;
}tn;
bool in(int x,int y)
{
    return x<=n&&x>0&&y<=m&&y>0;
}
void bfsf()
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    memset(vis,false,sizeof(vis));
    for(int i=0;i<sum;i++)
    {
        a.x=xx[i];a.y=yy[i];a.now=0;
        q.push(a);
        vis[a.x][b.y]=true;
    }
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.now=a.now+1;
            if(!g[b.x][b.y]&&in(b.x,b.y)&&!vis[b.x][b.y])
            {
                f[b.x][b.y]=b.now;
                vis[b.x][b.y]=true;
                q.push(b);
            }
        }
    }
}
int bfsj(int x,int y)
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    memset(vis,false,sizeof(vis));
    a.x=x;a.y=y;a.now=0;
    q.push(a);
    vis[x][y]=true;
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];b.now=a.now+1;
            if(!g[b.x][b.y]&&!vis[b.x][b.y]&&b.now<f[b.x][b.y])
            {
                if(!in(b.x,b.y))
                    return b.now;
                vis[b.x][b.y]=true;
                q.push(b);
            }
        }
    }
    return -1;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d%d",&n,&m);
        memset(g,0,sizeof(g));
        memset(f,0x3f,sizeof(f));
        sum=0;
        for(i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(j=1;j<=m;j++)
            {
                if(s[j-1]=='.')
                    continue;
                g[i][j]=1;
                if(s[j-1]=='J')
                    x=i,y=j;
                if(s[j-1]=='F')
                    xx[sum]=i,yy[sum++]=j;
            }
        }
        bfsf();
        t=bfsj(x,y);
        if(t==-1)
            printf("IMPOSSIBLE\n");
        else
            printf("%d\n",t);
    }
    return 0;
}

HDU1241 Oil Deposits

http://acm.hdu.edu.cn/showproblem.php?pid=1241
题意:
有很多@油井,周围一圈内可以连接在一起的油井在同一个油田中,求有多少油田。
思路:
bfs8个方向暴力即可。
code:
<pre name="code" class="cpp">#define N 112

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int g[N][N];
int dir[8][2]={1,0,1,1,1,-1,0,1,0,-1,-1,0,-1,-1,-1,1};
char s[101];
struct node
{
    int x,y;
}tn;
void bfs(int x,int y)
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    a.x=x;a.y=y;
    q.push(a);
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<8;i++)
        {
            b.x=a.x+dir[i][0];b.y=a.y+dir[i][1];
            if(g[b.x][b.y])
                q.push(b);
            g[b.x][b.y]=0;
        }
    }
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF&&n)
    {
        memset(g,0,sizeof(g));
        for(i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(j=1;j<=m;j++)
                if(s[j-1]=='@')
                    g[i][j]=1;
        }
        sum=0;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(g[i][j])
                {
                    sum++;
                    bfs(i,j);
                }
        printf("%d\n",sum);
    }
    return 0;
}


 

HDU1495 非常可乐

http://acm.hdu.edu.cn/showproblem.php?pid=1495
题意:
给出两个已知容量的杯子和一瓶可乐,杯子容量和等于可乐,求是否能平均分为两半,所需最少步骤。
思路:
奇数必然无解,偶数bfs,与前面分水那题基本相同。
code:

#define N 112345

int n,m,v,u;
int flag,sum,ave,ans,res,len,ans1,ans2;
bool vis[N];
char s[101];
struct node
{
    int x,y,z;
    int now;
}tn;
int bfs()
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    memset(vis,false,sizeof(vis));
    a.x=0;a.y=0;a.z=n;a.now=0;
    q.push(a);vis[0]=true;
    while(!q.empty())
    {
        a=q.front();q.pop();
        if(a.x==n/2||a.y==n/2||a.z==n/2)
            return a.x&&a.y&&a.z?a.now+1:a.now;
        b=a;
        b.x=u;b.z=a.z-(u-a.x);b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
        b=a;
        b.y=v;b.z=a.z-(v-a.y);b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
        b=a;
        b.x=0;b.z=a.z+a.x;b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
        b=a;
        b.y=0;b.z=a.z+a.y;b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
        b=a;
        b.x=min(u,a.x+a.y);b.y=max(a.x+a.y-u,0);b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
        b=a;
        b.y=min(v,b.x+b.y);b.x=max(a.x+a.y-v,0);b.now++;
        if(!vis[b.x*1000+b.y])
            q.push(b);
        vis[b.x*1000+b.y]=true;
    }
    return -1;
}
int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d%d",&n,&u,&v)!=EOF&&n)
    {
        t=n&1?-1:bfs();
        if(t==-1)
            printf("NO\n");
        else
            printf("%d\n",t);
    }
    return 0;
}


HDU2612 Find a way

http://acm.hdu.edu.cn/showproblem.php?pid=2612
题意:
Y和M要一起去一个kfc,每走一格需要11分钟,求他们去哪个kfc所需总时间和最少,
思路:
bfs两次,将两个人到每个kfc的时间打表,然后找出和最小的那个。
code:
#define N 212

int n,m;
int flag,sum,ave,ans,res,len,ans1,ans2;
int f[N][N],ff[N][N];
int g[N][N];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
bool vis[N][N];
char s[N];
struct node
{
    int x,y;
    int now;
}tn;
void bfsy(int x,int y)
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    a.x=x;a.y=y;a.now=0;
    q.push(a);
    f[x][y]=0;
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x+=dir[i][0];b.y+=dir[i][1];b.now++;
            if(g[b.x][b.y]&&f[b.x][b.y]==INF)
            {
                q.push(b);
                f[b.x][b.y]=b.now;
            }
        }
    }
}
void bfsm(int x,int y)
{
    queue<node>q;
    while(!q.empty())q.pop();
    node a,b;
    a.x=x;a.y=y;a.now=0;
    q.push(a);
    ff[x][y]=0;
    while(!q.empty())
    {
        a=q.front();q.pop();
        for(int i=0;i<4;i++)
        {
            b=a;
            b.x+=dir[i][0];b.y+=dir[i][1];b.now++;
            if(g[b.x][b.y]&&ff[b.x][b.y]==INF)
            {
                q.push(b);
                ff[b.x][b.y]=b.now;
            }
        }
    }
}
int main()
{
    int i,j,k,kk,t,x,y,xx,yy,z;
    while(scanf("%d%d",&n,&m)!=EOF&&n)
    {
        memset(g,0,sizeof(g));
        for(i=1;i<=n;i++)
        {
            scanf("%s",s);
            for(j=1;j<=m;j++)
            {
                if(s[j-1]=='#')
                    continue;
                g[i][j]++;
                if(s[j-1]=='@')
                    g[i][j]++;
                if(s[j-1]=='Y')
                    x=i,y=j;
                if(s[j-1]=='M')
                    xx=i,yy=j;
            }
        }
        memset(f,0x3f,sizeof(f));
        memset(ff,0x3f,sizeof(ff));
        bfsy(x,y);
        bfsm(xx,yy);
        res=INF;
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                if(g[i][j]==2)
                    res=min(res,f[i][j]+ff[i][j]);
        printf("%d\n",11*res);
    }
    return 0;
}

HDU-1430 魔板

http://blog.csdn.net/kopyh/article/details/48517595

HDU-3567 Eight II

http://blog.csdn.net/kopyh/article/details/48738709

HDU-2181 哈密顿绕行世界问题

http://blog.csdn.net/kopyh/article/details/48738747

HDU-3533 Escape

http://blog.csdn.net/kopyh/article/details/48738787

HDU-1560 DNA sequence

http://blog.csdn.net/kopyh/article/details/48738975

ZOJ-2477 Magic Cube

http://blog.csdn.net/kopyh/article/details/48739097

HDU-3085 Nightmare Ⅱ

http://blog.csdn.net/kopyh/article/details/48739333

HDU-1067 GAP

http://blog.csdn.net/kopyh/article/details/48739601

HDU-2102 A计划

http://blog.csdn.net/kopyh/article/details/48742173

HDU-3001 Travelling

http://blog.csdn.net/kopyh/article/details/48742311

HDU 5113 Black And White

http://blog.csdn.net/kopyh/article/details/48999173

HDU 4499 Cannon

http://blog.csdn.net/kopyh/article/details/49072247






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值