Description
小A和小B在一个R行S列的棋盘上玩游戏,棋盘上的每一个棋格都有一个方向标记(上、下、左或右)。游戏按如下方式进行:
小A先将K个棋格涂上黑色(初始为白色),并且他不能涂黑最后一列的棋格;随后,小B在第一列的任意一个棋格上放一个小机器人;此时,小机器人将会不停地沿着他所在的棋格所指示的方向走到一个相邻的棋格,直到他到达最后一列的棋格,游戏结束。
游戏胜负规则如下:
●如果小机器人最终到达最后一列,且在游戏过程中经过了恰好一个黑色棋格(包括小机器人开始的棋格),那么小A获得胜利;如果小机器人经过了零个或大于一个黑色格子,那么小B获得胜利。
●如果机器人永远无法停下来,那么小A胜利。
题目保证每个棋格上的方向标记不会让小机器人走到棋盘外。
棋盘示意图如下:
现在小A想知道,他是否能找到一种涂黑格子的方案,使得不论小B如何放置游戏开始时的小机器人,他都能取得游戏的胜利。
Solution
首先可以发现,一些属于环或是不会被走到的点可以任意染黑,剩下的点以可到达的最后一列点为根,就有若干多棵树组成森林,可以视作在树上的背包。当前节点可以不染黑当且仅当它的所有叶子节点到它的路径上只有一个点被染黑,然后在最后把所有的树都整合在一起。
Code
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,x) for(i=la[x];i;i=ne[i])
int F[4][2]={-1,0,1,0,0,-1,0,1};
const int N=1e6+5;
char ch;//0为未走过,1为环,2为可到达路径
int map[N],p[N],la[N],da[N],ne[N],f[N][55],h[N/10][55],node[N],to[N/10][55],ans[N/10][2],g[5][55];
bool bz[N];
int n,m,o,i,j,k,w,sum,num,tot,LEFT;
void ins(int x,int y){da[++sum]=y,ne[sum]=la[x],la[x]=sum;}
int W(int x,int y){return x*m-m+y;}
int dfs(int x,int y){
int w;
if(y==m) return 2;
w=W(x,y);
if(p[w]) return p[w];
if(bz[w]) return 1;
bz[w]=true;p[w]=dfs(x+F[map[w]][0],y+F[map[w]][1]);
if(p[w]==2) ins(W(x+F[map[w]][0],y+F[map[w]][1]),w);
return p[w];
}
void dp(int x){
int i,j,k;
f[x][0]=0;
if(x%m==1){
f[x][1]=node[x]=1;return;
}
rep(k,x){
dp(da[k]);
node[x]++;
for(i=o;i>=0;i--) if(f[x][i]==(node[x]-1)){
fo(j,1,o) if(f[da[k]][j]==node[da[k]]) f[x][i+j]=node[x];
}
}
f[x][1]=node[x];
}
void deal(int x,int tot){
if(tot==1){
printf("%d %d\n",x/m+1,x%m);
LEFT--;
return;
}
int i,j,k,A[5][2];
node[x]=0;g[0][0]=x;
rep(k,x){
node[x]++;
for(i=o;i>=0;i--) if(g[node[x]-1][i]==x){
fo(j,1,o) if(f[da[k]][j]==node[da[k]]) g[node[x]][i+j]=x,to[node[x]][i+j]=j;
}
A[node[x]][0]=da[k];
}
k=tot;i=node[x];
while(i>0&&tot>0){
A[i][1]=to[i][k];k-=to[i][k];i--;
}
i=node[x];
while(i>0){
deal(A[i][0],A[i][1]);
i--;
}
}
int main(){
freopen("robots.in","r",stdin);
freopen("robots.out","w",stdout);
scanf("%d%d%d\n",&n,&m,&o);
LEFT=o;
fo(i,1,n){
fo(j,1,m){
ch=getchar();
if(ch=='U') map[W(i,j)]=0;
if(ch=='D') map[W(i,j)]=1;
if(ch=='L') map[W(i,j)]=2;
if(ch=='R') map[W(i,j)]=3;
}
scanf("\n");
}
fo(i,1,n) if(!p[W(i,1)]) p[W(i,1)]=dfs(i,1);
tot=n*(m-1);
fo(i,1,n) fo(j,1,m-1) if(p[W(i,j)]==2) tot--;
memset(f,255,sizeof(f));
memset(h,255,sizeof(h));
fo(i,0,min(tot,o)) h[0][i]=0;
fo(i,1,n) if(la[W(i,m)]){
dp(W(i,m-1));
num++;w=W(i,m-1);
for(j=o-1;j>=0;j--) if(h[num-1][j]>=0){
fo(k,1,o-j) if(f[w][k]==node[w])
h[num][j+k]=w,to[num][j+k]=k;
}
}
if(h[num][o]<0){printf("-1\n");return 0;}
tot=o;i=num;
while(i>0&&tot>0){
ans[i][0]=h[i][tot];ans[i][1]=to[i][tot];
tot-=to[i][tot];i--;
}
i=num;
while(i>0){
deal(ans[i][0],ans[i][1]);
i--;
}
fo(i,1,n) fo(j,1,m-1) if(LEFT&&p[W(i,j)]!=2) printf("%d %d\n",i,j),LEFT--;
}