【NOI2017模拟4.5】机器人游戏【搜索,DP】

64 篇文章 0 订阅
26 篇文章 0 订阅

Description

小A和小B在一个R行S列的棋盘上玩游戏,棋盘上的每一个棋格都有一个方向标记(上、下、左或右)。游戏按如下方式进行:
小A先将K个棋格涂上黑色(初始为白色),并且他不能涂黑最后一列的棋格;随后,小B在第一列的任意一个棋格上放一个小机器人;此时,小机器人将会不停地沿着他所在的棋格所指示的方向走到一个相邻的棋格,直到他到达最后一列的棋格,游戏结束。
游戏胜负规则如下:
●如果小机器人最终到达最后一列,且在游戏过程中经过了恰好一个黑色棋格(包括小机器人开始的棋格),那么小A获得胜利;如果小机器人经过了零个或大于一个黑色格子,那么小B获得胜利。
●如果机器人永远无法停下来,那么小A胜利。
题目保证每个棋格上的方向标记不会让小机器人走到棋盘外。
棋盘示意图如下:
这里写图片描述
现在小A想知道,他是否能找到一种涂黑格子的方案,使得不论小B如何放置游戏开始时的小机器人,他都能取得游戏的胜利。

Solution

这道题目其实思路很好想,但是实现很麻烦,像我这样代码++的人一不小心就打了将近4000byte
首先,可以处理出那些在环上的点和走不到的点,那么这些点可以随便放。
然后很明显可以把图上联通的点建出一颗树,然后类似背包那样DP一下。
可以设f[i][j]表示做到i这个点,用了j个节点,是否能把它的儿子做完。
但是这样转移很麻烦,所以f[i][j]要存它做到第几个儿子,然后前面的儿子都做完并且儿子必须把它的儿子都做完才能转移。
然后树上DP完还要把每棵树的DP合并起来,这个DP和树上的很像。
最后求答案的时候先求出分配给每棵树多少个再dfs一次,然后用之前的DP值来求转移到哪去并输出。
最后如果不过,就把那些可以随便乱填的格子输出去。
怎么判断-1如果把树合并的那个DP不能成功分配,那么就输出-1.

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=1e6+7;
int i,j,k,l,t,n,m,ans,x,y;
int fang[4][2]={-1,0,1,0,0,-1,0,1};
char s[maxn];
int a[maxn],tot,op,b[maxn],c[maxn];
bool ui,cz[maxn],dz[maxn];
int first[maxn],next[maxn],last[maxn],num,S,sheng;
int size[maxn],sum,cnt,hou[maxn][2],top[maxn],fa[maxn/10][51];
int f[maxn][51],data[maxn][2],in[maxn],d[maxn/10][51],di[maxn][2];
int bz[maxn],id;
int de(int x,int y){return (x-1)*m+y;}
void add(int x,int y){
    last[++num]=y,next[num]=first[x],first[x]=num;
}
void dfs1(int xx,int yy){
    int j,k,x,y,o=0;
    k=a[de(xx,yy)];
    x=fang[k][0]+xx,y=fang[k][1]+yy;
    if(bz[de(x,y)])return;
    if(x>n||x<1||y>m-1||y<1)return;
    if(bz[de(x,y)]==id||cz[de(x,y)])return;
    bz[de(x,y)]=id;
    dfs1(x,y);
}
void bfs(){
    int head=0,tail=0,i,j,now,x,y,k;
    fo(i,1,n){
        if(!cz[de(i,1)]&&!in[de(i,1)])data[++tail][0]=i,data[tail][1]=1;
    }
    while(head<tail){
        i=data[++head][0],j=data[head][1];
        k=a[de(i,j)];
        x=i+fang[k][0],y=j+fang[k][1];
        if(y>m-1)continue;
        if(x==601){
            ans=ans;
        }
        add(de(x,y),de(i,j));dz[de(i,j)]=1;
        in[de(x,y)]--;
        if(!in[de(x,y)])data[++tail][0]=x,data[tail][1]=y;
    }
}
void dfs(int x){
    int i;
    f[x][0]=0;
    if(x%m==1){
        size[x]=f[x][1]=1;return;
    }
    rep(i,x){
        size[x]++;
        dfs(last[i]);
        fod(l,k,0){
            if(f[x][l]!=size[x]-1)continue;
            fo(j,0,k-l)if(f[last[i]][j]==size[last[i]])f[x][j+l]=size[x];
        }
    }   
    f[x][1]=size[x];
}
void dfs2(int x,int y){
    int i,j,l;
    if(y==1){
        printf("%d %d\n",di[x][0],di[x][1]);
        return;
    }
    d[0][0]=x;size[x]=0;
    rep(i,x){
        ++size[x];
        fod(j,k,0){
            if(d[size[x]-1][j]!=x)continue;
            fo(l,1,k-j)if(f[last[i]][l]==size[last[i]])d[size[x]][j+l]=x,fa[size[x]][j+l]=l;
        }
    }
    int fei[5],c[5];
    fei[0]=0;t=y;
    rep(i,x)fei[++fei[0]]=last[i];
    fod(i,fei[0],1)c[i]=fa[i][t],t-=fa[i][t];
    fo(i,1,fei[0])dfs2(fei[i],c[i]);
}
int main(){
    freopen("robots.in","r",stdin);
    freopen("robots.out","w",stdout);
 //   freopen("fan.in","r",stdin);
 //   freopen("fan.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    fo(i,1,n){
        scanf("%s",s+1);
        fo(j,1,m){
            if(s[j]=='U')a[++tot]=0;
            else if(s[j]=='D')a[++tot]=1;
            else if(s[j]=='L')a[++tot]=2;
            else a[++tot]=3;
            di[tot][0]=i,di[tot][1]=j;
        }
    }
    fo(i,1,n)if(!bz[de(i,1)])bz[de(i,1)]=++id,dfs1(i,1);
    fo(i,1,n)fo(j,1,m-1)
    if(!bz[de(i,j)]||cz[de(i,j)]) hou[++cnt][0]=i,hou[cnt][1]=j,cz[de(i,j)]=1;
    else{

        if(a[de(i,j)]==0)in[de(i-1,j)]++;
        else if(a[de(i,j)]==1)in[de(i+1,j)]++;
        else if(a[de(i,j)]==2){
            if(j!=2)in[de(i,j-1)]++;
        }
        else in[de(i,j+1)]++;
    }
    bfs();
    cnt=min(cnt,k);
    memset(f,255,sizeof(f));memset(d,255,sizeof(d));
    fo(i,0,cnt)d[0][i]=0;
    fo(i,1,n){
        if(!dz[de(i,m-1)]&&bz[de(i,m-1)])dfs(de(i,m-1));else continue;
        t=de(i,m-1);++op;top[op]=t;
        fod(j,k,0){
            if(d[op-1][j]!=op-1)continue;
            fo(l,0,k-j)if(f[t][l]==size[t])d[op][j+l]=op,fa[op][j+l]=l;
        }
    }
    if(d[op][k]<0)printf("-1\n");
    else{
        int u=0;t=k;
        fod(i,op,1)
        b[++u]=top[i],c[u]=fa[i][t],t-=fa[i][t];
        int p=t;
        fo(i,1,u){
            dfs2(b[i],c[i]);
        }
        fo(i,1,cnt){
            if(!p)break;p--;
            printf("%d %d\n",hou[i][0],hou[i][1]);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值