【NOI2017模拟4.5】机器人游戏
2017-04-10 10:46
363 查看
题目
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.
相关文章推荐
- 【NOI2017模拟4.5】机器人游戏【搜索,DP】
- 【JZOJ5046】【NOI2017模拟4.5】机器人游戏
- 【NOI2017模拟4.5】数字格
- 【NOI2017模拟4.5】无限棋盘
- 【JZOJ5045】【NOI2017模拟4.5】无限棋盘
- 【NOI2017模拟4.5】无限棋盘【哈希,字符串,倍增】
- 【NOI2017】机器人游戏
- J题 游戏模拟
- 【JZOJ 100019】【NOI2017模拟6.26】A
- 【机器人系列】支付宝支付控件输入框模拟输入
- 【Visual C++】游戏开发笔记二十 游戏基础物理建模(二) 重力系统的模拟
- 【Visual C++】游戏开发笔记二十二 游戏基础物理建模(四) 粒子系统模拟(一)
- 【Visual C++】游戏开发笔记二十三 游戏基础物理建模(五) 粒子系统模拟(二)
- 【程序12】模拟掷骰子游戏
- Android提高之手游转电视游戏的模拟操控
- 基于 flask 框架的模拟instagram 图片分享网站的开发 7 (爬虫机器人)
- 模拟条件超简单的细胞繁衍游戏之二
- 游戏模拟系统Lakka稳定版发布
- 网路游戏之物理模拟
- bzoj4549 LOJ2305 NOI2017 游戏 2-sat