hdu 5335 Walk Out 2015 Multi-University Training Contest 4

因为前缀0对答案没有影响,所以可以先BFS找出起点经过0可以到达的1,这些1作为新的起点。二进制数位数越少那么值越小,所以应该找距离(n,m)最近,即n-x+m-y+1最小的点(可能有多个)。并且搜索时只能沿下或右方向搜索。因为如果向左方或上方搜索,二进制数的总位数必然增加,且最高位是1,所以值只会增大。

然后我卡在了是否搜索到了(n,m)就要输出。比如一下这种case,

100

000

011

如果先搜下再搜右,路径是10011,如果先搜右再搜下,路径是10001。所以不能先到达终点就输出结果,当然也可以全部存起来最后在比较。><

有一种trick是如果BFS的某一层里有0,那么这一层的1都不搜索。而是否有0可以在扩展子节点的过程中进行判断。因为BFS的层数可以对应到二进制数的某一位,这样就保证了某一位优先选0。

最后注意如果在找起点的BFS过程中扩展到了(n,m),那么说明可以直接经过一系列0到达终点,这种case需要特判。否则再从其他1开始搜索会WA。

臣妾先是忘记标记vis数组重复扩点导致MLE,然后忘了初始化数组导致WA=。=

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<ctype.h>
#include<map>
#include<time.h>
#include<bitset>
#include<set>
#include<list>
using namespace std;
//hdu 5335

const int maxn=1010;
const int INF=0x3f3f3f3f;
int T;
int n;
int m;
int dx[]={0,-1,0,1};
int dy[]={-1,0,1,0};
int mp[maxn][maxn];
bool vis[maxn][maxn];
int dis[maxn][maxn];
bool existzero[maxn];
vector<pair<int,int> >start;
pair<int,int>pre[maxn][maxn];
int minlen;
bool flgnone;
void bfs_start()
{
    minlen=INF;
    if(mp[1][1]==1)
    {
        start.push_back(make_pair(1,1));
        minlen=n+m-1;
        return;
    }
    queue<pair<int,int> >que;
    que.push(make_pair(1,1));
    vis[1][1]=true;
    pair<int,int>now;
    while(!que.empty())
    {
        now=que.front();
        que.pop();
        if(now.first==n&&now.second==m)//we need to judge it here not in the loop of expansion process
        {//if there is only one point which is zero.
            flgnone=true;
            return;
        }
        for(int i=0;i<4;i++)
        {
            int x=now.first+dx[i];
            int y=now.second+dy[i];
            if(x<1||x>n||y<1||y>m) continue;
            if(vis[x][y]) continue;
            if(mp[x][y]==0)
            {
                que.push(make_pair(x,y));
                vis[x][y]=true;
            }
            else
            {
                start.push_back(make_pair(x,y));
                vis[x][y]=true;
                int tmp=n+m-x-y+1;
                if(minlen>tmp)
                {
                    minlen=tmp;
                }
            }
       }
    }
    return;
}
void print(int x,int y)
{
    if(pre[x][y].first==0&&pre[x][y].second==0)
    {
        printf("%d",mp[x][y]);
        return;
    }
    print(pre[x][y].first,pre[x][y].second);
    printf("%d",mp[x][y]);
}
void solve()
{
    queue<pair<int,int> >que;//maybe there more than one start point
   // cout<<start.size()<<endl;
    for(int i=0;i<start.size();i++)
    {
      //  cout<<start[i].first<<" "<<start[i].second<<endl;
        int tmp=n+m-start[i].first-start[i].second+1;
        if(minlen==tmp)
        {
           que.push(start[i]);
           vis[start[i].first][start[i].second]=true;
           pre[start[i].first][start[i].second]=make_pair(0,0);
           dis[start[i].first][start[i].second]=1;
        }
    }
    existzero[1]=0;
    pair<int,int>now;
    while(!que.empty())
    {
        now=que.front();
        que.pop();
        if(now.first==n&&now.second==m)
        {
            print(now.first,now.second);
            return;
//            if(pre[now.first][now.second].first!=0&&pre[now.first][now.second].second!=0)
//            {
//                print(now.first,now.second);
//                return;
//            }
        }
        if(existzero[dis[now.first][now.second]]==1&&mp[now.first][now.second]==1)
        {
            continue;
        }
        for(int i=2;i<4;i++)
        {
            int x=now.first+dx[i];
            int y=now.second+dy[i];
            if(x<1||x>n||y<1||y>m) continue;
            if(vis[x][y]) continue;
            que.push(make_pair(x,y));
            pre[x][y]=now;
            vis[x][y]=true;
            dis[x][y]=dis[now.first][now.second]+1;
            if(mp[x][y]==0)
            {
                existzero[dis[x][y]]=1;
            }
        }
    }
    return;
}
int main()
{
    freopen("input.txt","r",stdin);
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        scanf("%d %d",&n,&m);
        memset(vis,false,sizeof(vis));
        memset(dis,0,sizeof(dis));
        memset(mp,0,sizeof(mp));
        memset(pre,0,sizeof(pre));
        memset(existzero,0,sizeof(existzero));
        start.clear();
        flgnone=false;
        char str[maxn];
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str+1);
            for(int j=1;j<=m;j++)
            {
                mp[i][j]=str[j]-'0';
            }
        }
//        cout<<n<<" nm "<<m<<endl;
//        for(int i=1;i<=n;i++)
//        {
//            for(int j=1;j<=m;j++)
//            {
//                cout<<mp[i][j]<<" ";
//            }
//            cout<<endl;
//        }
//        cout<<"ed1"<<endl;
        bfs_start();
        if(flgnone==true)
        {
            printf("0\n");
            continue;
        }
        solve();
        puts("");
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值