[NWPU] 01-22 Coding Marathon

A.[BFS]Pushing Boxes, SWERC 1997, Uva589
题意:在一个给定的迷宫中,输入一个人和一个箱子的初始位置以及终点的位置,问能否使人将箱子推到终点,若能则输出人的全部路径。

题解:迷宫中不仅需要考虑箱子能否行进到终点,还需考虑人能否走到推箱子的位置。因此首先需要对箱子BFS,在箱子走每一步的时候都对人进行第二个BFS判断能否走到推箱子的位置。存储路径的时候选用string,因其可以方便地与另外一个串或字符相加。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 25
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef long long ll;

int n,m,kase=0;
int sx,sy,bx,by,ex,ey;
char maze[maxn][maxn];
bool flag[maxn][maxn];
bool vis[maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
char pos[2][5]={"SENW","senw"};
struct Node
{
    int x,y;
    int rx,ry;
    string route;
}now,net;
struct node
{
    int x,y;
    string route;
}cur,nxt;

bool judge(int x,int y)
{
    if(x>=0&&y>=0&&x<n&&y<m&&maze[x][y]!='#')
        return true;
    return false;
}

bool bfs2(int stx,int sty,int enx,int eny)
{
    memset(vis,0,sizeof(vis));
    node sta;
    sta.x=stx,sta.y=sty;
    queue<node>que;
    sta.route="";
    vis[stx][sty]=1;
    vis[now.x][now.y]=1;
    que.push(sta);
    while(!que.empty())
    {
        cur=que.front();
        que.pop();
        if(cur.x==enx&&cur.y==eny)
            return true;
        for(int i=0;i<4;i++)
        {
            nxt.x=cur.x+dir[i][0];
            nxt.y=cur.y+dir[i][1];
            if(judge(nxt.x,nxt.y)&&!vis[nxt.x][nxt.y])
            {
                nxt.route=cur.route+pos[1][i];
                vis[nxt.x][nxt.y]=1;
                que.push(nxt);
            }
        }
    }
    return false;
}

bool bfs()
{
    memset(flag,0,sizeof(flag));
    Node st;
    queue<Node>q;
    st.x=bx,st.y=by;
    st.rx=sx,st.ry=sy;
    st.route="";
    q.push(st);
    flag[bx][by]=1;
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            net.x=now.x+dir[i][0];
            net.y=now.y+dir[i][1];
            int kx=now.x-dir[i][0];
            int ky=now.y-dir[i][1];
            if(judge(net.x,net.y)&&!flag[net.x][net.y]&&judge(kx,ky)&&bfs2(now.rx,now.ry,kx,ky))
            {
                net.route=now.route+cur.route+pos[0][i];
                flag[net.x][net.y]=1;
                net.rx=now.x,net.ry=now.y;
                if(net.x==ex&&net.y==ey)
                    return true;
                q.push(net);
            }
        }
    }
    return false;
}

int main()
{
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        kase++;
        for(int i=0;i<n;i++)
        {
            scanf("%s",maze[i]);
            for(int j=0;j<m;j++)
            {
                if(maze[i][j]=='S')
                    sx=i,sy=j;
                else if(maze[i][j]=='B')
                    bx=i,by=j;
                else if(maze[i][j]=='T')
                    ex=i,ey=j;
            }
        }
        printf("Maze #%d\n",kase);
        if(bfs())
            cout<<net.route<<endl;
        else
            printf("Impossible.\n");
        printf("\n");
    }
    return 0;
}

B.[BFS+哈希]The Warehouse,CERC2005,UvaLive3528
题意:一个n*n的迷宫由若干个小正方体木块堆叠而成,有的位置上有多个木块,也有的位置上没有木块。现给定起点与终点,问能否从起点走到终点,若能则求出步数。
规定在迷宫中人只能站立在木块上,当人站在木块上时它可以进行两种操作:一种是向着某个方向走一格,只能走到相邻的木块上且不限制高度;另一种是当脚下的木块数量多于一个时,人可以向着某个方向将脚下的木块推倒,但必须保证所有的木块都落在空地上(终点不能看作空地)。只有行进的时候算一步,推倒木块不算一步。

题解:与一般的BFS 不同,这个问题增加了推倒木块的操作。推倒木块必然引起地图变化,因此这个图的状态不好处理,map显然并不好搞。图最大只有8*8,把整张地图作为一个字符串hash掉放进一个表里,每次扩展状态的时候看是否在表中出现过。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 10
#define maxm 100050
#define INF 0x3f3f3f3f
#define eps 1e-6
const int mod=300007;
using namespace std;
typedef long long ll;

int n,sx,sy,ex,ey,no;
int head[mod],nex[mod];
char maze[maxn][maxn];
int dir[4][2]={1,0,0,1,-1,0,0,-1};
struct node
{
    int x,y;
    int step;
    char s[maxn][maxn];
}e[maxm],now,nxt;

void init()
{
    no=0;
    memset(head,-1,sizeof(head));
    memset(nex,-1,sizeof(nex));
}

bool equall(node a,node b)
{
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            if(a.s[i][j]!=b.s[i][j])
                return false;
    }
    if(a.x==b.x&&a.y==b.y)
        return true;
    return false;
}

int gethash(node a)
{
    int sum=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(a.s[i][j]>='1'&&a.s[i][j]<='9')
            {
                sum=sum*31+a.s[i][j]-'0';
                sum%=mod;
            }
        }
    }
    sum=sum*31+a.x,sum%=mod;
    sum=sum*31+a.y,sum%=mod;
    return sum;
}

bool judge(int x,int y)
{
    if(x>=0&&y>=0&&x<n&&y<n)
        return true;
    return false;
}

bool judgehash(int ha,node tmp)
{
    int u=head[ha];
    while(u!=-1)
    {
        if(equall(tmp,e[u]))
            return false;
        u=nex[u];
    }
    e[no]=tmp;
    nex[no]=head[ha];
    head[ha]=no++;
    return true;
}

bool judgepush(int i)
{
    int kx=nxt.x-dir[i][0];
    int ky=nxt.y-dir[i][1];
    int num=nxt.s[kx][ky]-'0';
    for(int j=1;j<=num;j++)
    {
        kx+=dir[i][0];
        ky+=dir[i][1];
        if(!judge(kx,ky)||nxt.s[kx][ky]!='.')
            return false;
    }
    kx=nxt.x-dir[i][0],ky=nxt.y-dir[i][1];
    nxt.s[kx][ky]='.';
    for(int j=1;j<=num;j++)
    {
        kx+=dir[i][0];
        ky+=dir[i][1];
        nxt.s[kx][ky]='1';
    }
    return true;
}

int bfs()
{
    queue<node>q;
    node st;
    st.x=sx,st.y=sy,st.step=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
            st.s[i][j]=maze[i][j];
    }
    q.push(st);
    while(!q.empty())
    {
        now=q.front();
        q.pop();
        if(now.x==ex&&now.y==ey)
            return now.step;
        for(int i=0;i<4;i++)
        {
            int nx=now.x+dir[i][0];
            int ny=now.y+dir[i][1];
            if(judge(nx,ny))
            {
                nxt=now;
                nxt.step++,nxt.x=nx,nxt.y=ny;
                if(nxt.s[nx][ny]!='.')
                {
                    int cur=gethash(nxt);
                    if(judgehash(cur,nxt))
                        q.push(nxt);
                }
                if(now.s[now.x][now.y]!='1'&&judgepush(i))
                {
                    int cur=gethash(nxt);
                    if(judgehash(cur,nxt))
                        q.push(nxt);
                }
            }
        }
    }
    return -1;
}

int main()
{
    while(scanf("%d%d%d",&n,&sx,&sy))
    {
        if(n==0&&sx==0&&sy==0)break;
        sx--,sy--;
        init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",maze[i]);
            for(int j=0;j<n;j++)
            {
                if(maze[i][j]=='E')
                    ex=i,ey=j;
            }
        }
        int ans=bfs();
        if(ans==-1)
            printf("Impossible.\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

C.[二分+匹配]Mysterious Mountain, Uva10122
题意:给出n个山头的坐标和n个人的初始坐标。现在要使这n个人每人登上一个不同的山头,人在登山的时候可以选择以w的速度在平地上走一段到某个整点,再以c的速度直线攀爬。问要使所有人各自登上一个山头,最少需要多少时间。

题解:可以预处理出每个人到达每个山头的最短时间。但登山点并不是任意选择,由于不同的山峰之间存在高度差,人是不能在空气中直线攀爬的,这就限制了登山点的范围。由于要求的是整点,只需枚举符合要求的区间中的整点。n个人爬上n个山头,这显然是一个二分图的完美匹配,但与最大权匹配不同,这个问题要求最大边权最小。采用的方法是:二分处理所需的时间,每次都建一个新图遍历一遍所有原有的边,如果花费时间小于当前的值,就令在新图上连这条边。判断新图能否构成完美匹配。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#define maxn 105
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long ll;
int n;
double maxt;
double maze[maxn][maxn];
int s[maxn],c[maxn],w[maxn];
bool vis[maxn],flag[maxn][maxn];
int linker[maxn];
struct node
{
    int x,y;
}e[maxn];

double Min(double a,double b)
{
    return a<b?a:b;
}

double Max(double a,double b)
{
    return a>b?a:b;
}

double mintime(int i,int j)
{
    double ans=1.0*INF;
    int l,r;
    if(s[i]<e[j].x)
    {
        r=e[j].x;
        l=s[i];
        for(int k=0;k<j;k++)
        {
            if(e[k].y<e[j].y)
            {
                double cnt=1.0*(e[k].x*e[j].y-e[k].y*e[j].x)/(e[j].y-e[k].y);
                l=max(l,(int)(cnt-eps)+1);
            }
        }
    }
    else
    {
        r=s[i];
        l=e[j].x;
        for(int k=n+1;k>j;k--)
        {
            if(e[k].y<e[j].y)
            {
                double cnt=1.0*(e[k].x*e[j].y-e[k].y*e[j].x)/(e[j].y-e[k].y);
                r=min(r,(int)(cnt+eps));
            }
        }
    }
    for(int p=l;p<=r;p++)
    {
        int tmp=p;
        ans=Min(ans,abs(tmp-s[i])*1.0/(w[i]*1.0)+sqrt(1.0*((tmp-e[j].x)*(tmp-e[j].x)+e[j].y*e[j].y))/(c[i]*1.0));
    }
    return ans;
}

bool dfs(int x)
{
    for(int y=1;y<=n;y++)
    {
       if(flag[x][y]&&!vis[y])
       {
           vis[y]=true;
           if(linker[y]==-1||dfs(linker[y]))
           {
               linker[y]=x;
               return true;
           }
       }
    }
    return false;
}

int hungury()
{
    memset(linker,-1,sizeof(linker));
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;
    }
    return ans;
}

double solve()
{
    double l=0,r=maxt;
    while(fabs(r-l)>eps)
    {
        double mid=(l+r)/2;
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
                if(maze[i][j]<=mid)
                    flag[i][j]=1;
        }
        if(hungury()>=n)
            r=mid;
        else
            l=mid;
    }
    return (l+r)/2;
}

int main()
{
    while(scanf("%d",&n))
    {
        if(n==0)break;
        for(int i=0;i<=n+1;i++)
            scanf("%d%d",&e[i].x,&e[i].y);
        maxt=-1.0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&c[i],&w[i],&s[i]);
            for(int j=1;j<=n;j++)
            {
                maze[i][j]=mintime(i,j);
                maxt=Max(maxt,maze[i][j]);
            }
        }
        double ans=solve();
        printf("%.2lf\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值