您的位置:首页 > 其它

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

2017-04-06 17:17 447 查看

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]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: