【NOI2017模拟4.5】机器人游戏

题目

Description

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

现在小A想知道,他是否能找到一种涂黑格子的方案,使得不论小B如何放置游戏开始时的小机器人,他都能取得游戏的胜利。

Input

第一行包含三个正整数R,S,K(1<=R*S<=1,000,000,1<=K<=50)。
接下来R行,每行S个字符’L’(左),’R’(右),’U’(上),’D’(下),表示每个棋格的方向标志。

Output

如果小A没有必胜策略,输出-1。
否则,输出K行,每行两个正整数A,B(1<=A<=R,1<=B<=S)表示小A要涂黑的棋格。输出不能有两个相同的棋格。
如果有多种不同的方案,输出任意一种即可。

Sample Input

输入1:
4 3 1
DRD
DUD
DUD
RUL
输入2:
3 3 2
RRR
RRR
RRR
输入3:
4 4 2
RRDL
RRDL
DLRD
RRRL

题解

考虑建一颗树来解决这个问题
我们先把所有的箭头都反向,把最后一列整体看成一个节点,然后按照箭头连边
容易发现,如果一颗子树里的每一个节点都不是第一列的,那么这颗子树中所有节点都可以涂黑可以不涂黑,现在关键是如何处理其他的节点
考虑用一个dp解决这个问题,设f[i,j]表示以i为根的子树里面j个涂黑是否可以合法,转移显然
得到答案之后我们可以从根开始再做一遍dfs,随便找一下选哪一些点就可以了
但是我们发现这样会超时,于是打一个水优化,就是树里面可能会有一些连续的且不经过第一列的链,我们可以把这个链缩成一个点,这样实际复杂度就变得十分的优秀了

贴代码

var
    go:array[1..4,1..2]of longint=((-1,0),(0,1),(1,0),(0,-1));
    h,a,fa,fi:array[0..1000005]of longint;
    son:array[0..1000005,0..4]of longint;
    f,g:array[0..1000005,0..51]of boolean;
    cc,pc:array[0..55,0..55]of longint;
    bz,bc:array[0..1000005]of boolean;
    dui:array[1..4]of longint=(3,4,1,2);
    i,j,k,l,r,s,kk,x,y,z,n,ss,cq:longint;
    ch:char;
    bt:boolean;
function zhuan(x,y:longint):longint;
begin
    bt:=false;
    if y=1 then
    begin
        if x<=s then bt:=true;
        exit(x-s);
    end else
    if y=3 then
    begin
        if x+s>r*s then bt:=true;
        exit(x+s);
    end else
    if y=2 then
    begin
        if x mod s=0 then bt:=true;
        exit(x+1);
    end else
    begin
        if x mod s=1 then bt:=true;
        exit(x-1);
    end;
end;
procedure bfs;
var
    yy:longint;
begin
    i:=x;
    j:=0;
    while i>j do
    begin
        inc(j);
        x:=h[j];
        for k:=1 to 4 do
        begin
            y:=zhuan(x,k);
            if (bt=true) or (bz[y]=true) or (a[y]<>dui[k]) then continue;
            if y mod s=0 then continue;
            fa[y]:=x;
            if y mod s=1 then
            begin
                yy:=y;
                while (bc[yy]=false) and (yy<>0) do
                begin
                    if yy mod s=0 then
                    begin
                        yy:=yy;
                    end;
                    bc[yy]:=true;
                    yy:=fa[yy];
                    inc(ss);
                end;
            end;
            inc(son[x,0]);
            son[x,son[x,0]]:=y;
            inc(i);
            h[i]:=y;
            bz[y]:=true;
        end;
    end;
end;
procedure dfs(x:longint);
var
    i,j,k,ci:longint;
begin
    f[x,0]:=true;
    ci:=0;
    while (son[x,0]=1) and (son[son[x,1],0]<>0) do
    begin
        if son[x,1] mod s=1 then break;
        son[x]:=son[son[x,1]];
    end;
    for i:=1 to son[x,0] do
    if bc[son[x,i]]=true then
    begin
        dfs(son[x,i]);
        if (x-1) mod s=0 then continue;
        for j:=1 to kk do g[x,j]:=false;
        for j:=kk downto 1 do
        begin
            //if f[son[x,i],j]=false then f[x,j]:=false;
            if f[x,j]=false then
                for k:=0 to j-1 do
                if (f[son[x,i],j-k]=true) and (f[x,k]=true) then g[x,j]:=true;
        end;
        for j:=0 to kk do f[x,j]:=g[x,j];
    end;
    f[x,0]:=false;
    f[x,1]:=true;
    if x=11 then
    begin
        x:=x;
    end;
end;
procedure back(x,y:longint);
var
    i,j,ls:longint;
    pc,cc:array[0..55,0..55]of longint;
begin
    fillchar(cc,sizeof(cc),0);
    fillchar(pc,sizeof(pc),0);
    for i:=1 to y do f[x,i]:=false;
    f[x,0]:=true;
    for i:=1 to son[x,0] do
    if bc[son[x,i]]=true then
    begin
        for j:=1 to y do g[x,j]:=false;
        for j:=y downto 1 do
        begin
            //if f[son[x,i],j]=false then f[x,j]:=false;
            for k:=0 to j-1 do
            if (f[son[x,i],j-k]=true) and (f[x,k]=true) then
            begin
                g[x,j]:=true;
                cc[j]:=cc[k];
                pc[j]:=pc[k];
                inc(cc[j,0]); cc[j,cc[j,0]]:=son[x,i];
                pc[j,cc[j,0]]:=j-k;
            end;
        end;
        for j:=0 to kk do f[x,j]:=g[x,j];
    end;
    for i:=1 to cc[y,0] do
    begin
        if pc[y,i]=1 then writeln(cc[y,i] div s+1,' ',cc[y,i] mod s) else
        back(cc[y,i],pc[y,i]);
    end;
end;
begin
    assign(input,'robots.in'); reset(input);
    assign(output,'robots.out'); rewrite(output);
    readln(r,s,kk);
    for i:=1 to r do
    begin
        for j:=1 to s do
        begin
            read(ch);
            if ch='U' then x:=1 else
            if ch='R' then x:=2 else
            if ch='D' then x:=3 else
            if ch='L' then x:=4;
            a[(i-1)*s+j]:=x;
        end;
        readln;
    end;
    x:=0;
    for i:=1 to r do
    if a[(i-1)*s+s-1]=2 then
    begin
        inc(x);
        h[x]:=(i-1)*s+s-1;
        bz[(i-1)*s+s-1]:=true;
        fi[x]:=h[x];
    end;
    n:=x;
    bfs;
    for i:=1 to n do
    if bc[fi[i]]=true then
    dfs(fi[i]);
    f[r*s,0]:=true;
    for i:=1 to n do
    if bc[fi[i]]=true then
    begin
        for j:=1 to kk do g[r*s,j]:=false;
        for j:=kk downto 1 do
        begin
            //if f[fi[i],j]=false then f[r*s,j]:=false;
            for k:=0 to j-1 do
            if (f[fi[i],j-k]=true) and (f[r*s,k]=true) then
            begin
                g[r*s,j]:=true;
                cc[j]:=cc[k];
                pc[j]:=pc[k];
                inc(cc[j,0]); cc[j,cc[j,0]]:=i;
                pc[j,cc[j,0]]:=j-k;
            end;
        end;
        for j:=0 to kk do f[r*s,j]:=g[r*s,j];
    end;
    bt:=false;
    ss:=r*(s-1)-ss;
    cq:=kk-ss; if cq<0 then cq:=0;
    for i:=kk downto cq do
    if (f[r*s,i]=true) then
    begin
        bt:=true;
        k:=i;
        for j:=1 to r*s do if (j mod s>1) and (bc[j]=false) then
        begin
            if k=kk then break;
            writeln(j div s+1,' ',j mod s);
            inc(k);
        end;
        break;
    end;
    if bt=false then writeln(-1) else
    begin
        kk:=i;
        j:=1;
        for i:=1 to n do
        if cc[kk,j]=i then
        begin
            if pc[kk,j]=1 then
            begin
                writeln(fi[i] div s+1,' ',fi[i] mod s);
                inc(j);
                continue;
            end;
            back(fi[i],pc[kk,j]);
            inc(j);
            if j>cc[kk,0] then break;
        end;
    end;
    close(input); close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值