[JZOJ5046]机器人游戏

来源:互联网 发布:马踏棋盘 栈 贪婪算法 编辑:程序博客网 时间:2024/04/30 20:33

题目描述

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

1R×S106,1K50


题目分析

排除掉不会走到的格子以及会死循环的格子,所有格子都构成了一个森林。
现在的问题是要涂黑K个点,使得每一个对应于第一列的点都有且仅有一个被涂黑的祖先。
这个问题存在树形依赖关系,可以使用很套路的DFS序dp:
fi,j表示做到DFS序的第i个点,已经涂黑了j个点,是否能使前i1个点都合法。瞎讨论转移一下就好了。
注意因为那些不在森林上的点也可以涂黑,最后我们把它们的贡献考虑进去就好了。
记录方案的话,因为这题卡空间,所以我们记录涂黑点数直接用一个bool记录是否新涂黑了点就好了。
时间复杂度O(RSK)


代码实现

#include <iostream>#include <cstdio>#include <cctype>using namespace std;const int N=1000050;const int MAXK=55;int vis[N],fa[N],DFN[N],last[N],tov[N],nxt[N],size[N],p[N];int black[MAXK][2];bool dk[N][MAXK];bool f[N][MAXK];int g[N][MAXK];char MAP[N];int row,col,K,tot,idx,REM,bs;bool win;int getid(int x,int y){return x*col+y;}void getxy(int id,int &x,int &y){x=id/col,y=id%col;}void insert(int x,int y){tov[++tot]=y,nxt[tot]=last[x],last[x]=tot;}bool simulation(int x,int y,int cnt){    int id=getid(x,y);    if (vis[id]==cnt) return 0;    if (vis[id]) return 1;    vis[id]=cnt;    if (MAP[id]=='L') --y;    if (MAP[id]=='R') ++y;    if (MAP[id]=='U') --x;    if (MAP[id]=='D') ++x;    if (y+1==col) return 1;    int id_=getid(x,y);    return fa[id]=id_,simulation(x,y,cnt);}void dfs(int x){    p[DFN[x]=++idx]=x,size[x]=1;    for (int i=last[x],y;i;i=nxt[i]) if ((y=tov[i])!=fa[x]) dfs(y),size[x]+=size[y];}void dp(){    win=0,f[1][0]=1;    for (int x=1;x<=idx;++x)        for (int k=0;k<=K;++k)            if (f[x][k])            {                if ((p[x]%col)&&!f[x+1][k]) f[x+1][k]=1,g[x+1][k]=x,dk[x+1][k]=0;                if (k<K&&!f[x+size[p[x]]][k+1]) f[x+size[p[x]]][k+1]=1,g[x+size[p[x]]][k+1]=x,dk[x+size[p[x]]][k+1]=1;            }    for (int k=0;k<=K;++k)        if (f[idx+1][k]&&K-REM<=k)        {            win=1;            for (int id=g[idx+1][k],k_=k-dk[idx+1][k],k__=k;id!=0;k__=k_,k_-=dk[id][k_],id=g[id][k__])                if (k_!=k__) ++bs,getxy(p[id],black[bs][0],black[bs][1]),++black[bs][0],++black[bs][1];            REM=K-k;            for (int x=0;x<row*col&&bs<K;++x) if (!DFN[x]&&(x%col!=col-1)) ++bs,getxy(x,black[bs][0],black[bs][1]),++black[bs][0],++black[bs][1];            break;        }}int main(){    freopen("robots.in","r",stdin),freopen("robots.out","w",stdout);    scanf("%d%d%d",&row,&col,&K);    for (int i=0;i<row;++i)        for (int j=0;j<col;++j)        {            char ch=getchar();            while (!isalpha(ch)) ch=getchar();            MAP[getid(i,j)]=ch;        }    win=0;    if (col>1&&row*(col-1)>=K)    {        for (int x=0;x<row*col;++x) fa[x]=-1;        for (int i=0;i<row;++i) simulation(i,0,i+1);        REM=idx=0;        for (int x=0;x<row*col;++x) if (fa[x]!=-1) insert(fa[x],x);        for (int x=0;x<row*col;++x) if (vis[x]&&fa[x]==-1) dfs(x);        REM=row*(col-1)-idx,dp();    };    if (!win) printf("-1\n");    else for (int i=1;i<=K;++i) printf("%d %d\n",black[i][0],black[i][1]);    fclose(stdin),fclose(stdout);    return 0;}
0 0
原创粉丝点击