Codeforces 327D Block Tower【BFS+优先队列】


D. Block Tower


time limit per test 2 seconds

memory limit per test     256 megabytes


After too muchplaying on paper, Iahub has switched to computer games. The game he plays iscalled "Block Towers". It is played in a rectangular grid with n rows and m columns (itcontains n × m cells). The goal of the game is to build your own city. Some cells in thegrid are big holes, where Iahub can't build any building. The rest of cells areempty. In some empty cell Iahub can build exactly one tower of two followingtypes:

1.Blue towers. Each has population limitequal to 100.

2.Red towers. Each has population limitequal to 200. However, itcan be built in some cell only if in that moment at least one of theneighbouring cells has a Blue Tower. Two cells are neighbours is they share aside.

Iahub is alsoallowed to destroy a building from any cell. He can do this operation as muchas he wants. After destroying a building, the other buildings are notinfluenced, and the destroyed cell becomes empty (so Iahub can build a tower inthis cell if needed, see the second example for such a case).

Iahub can convinceas many population as he wants to come into his city. So he needs to configurehis city to allow maximum population possible. Therefore he should find asequence of operations that builds the city in an optimal way, so that totalpopulation limit is as large as possible.

He says he's thebest at this game, but he doesn't have the optimal solution. Write a programthat calculates the optimal one, to show him that he's not as good as hethinks.

Input

The first lineof the input contains two integersn and m (1 ≤ n, m ≤ 500). Each of the next n lines contains m characters, describing the grid. The j-th character in the i-th line is '.' if you're allowed to build at the cell with coordinates (i, j) a tower (empty cell) or '#' if there is abig hole there.

Output

Print an integerk in the first line (0 ≤ k ≤ 106) — the number of operations Iahub should perform to obtain optimal result.

Each of thefollowingk lines mustcontain a single operation in the following format:

1.«B x y»(1 ≤ x ≤ n, 1 ≤ y ≤ m) — building a blue tower at the cell (x, y);

2.«R x y»(1 ≤ x ≤ n, 1 ≤ y ≤ m) — building a red tower at the cell (x, y);

3.«D x y»(1 ≤ x ≤ n, 1 ≤ y ≤ m) — destroying a tower at the cell (x, y).

If there are multiple solutions you canoutput any of them. Note, that you shouldn't minimize the number of operations.

Examples

Input

2 3
..#
.#.

Output

4
B 1 1
R 1 2
R 2 1
B 2 3

Input

1 3
...

Output

5
B 1 1
B 1 2
R 1 3
D 1 2
R 1 2

 


题意:有一个n*m的矩形,'.'表示空地,'#'表示这个地方有一个大洞(即不能造建筑),你可以在空地上造建筑,建筑有两种,一种是蓝色的,可以容纳100人,能建造在任何位置,还有一种是红色的,可以容纳200人,它必须被建造在蓝色建筑的边上,也就是说红色建筑的上下左右必须有一位置上有蓝色建筑。同时你可以对建筑进行拆除,问怎样建造能容纳的人总数最多,并输出方案(不要求操作数最小化)。


思路:显然,我们应该要尽可能多的建造红色建筑,又因为蓝色建筑可以建造在任何空地上,所以我们先把所有空地上都建造蓝色建筑,然后我们应该尽可能在满足条件的情况下拆除一些蓝色建筑并在上面建造红色建筑。


容易想到,开始蓝色建筑可以构成很多歌联通块,而每个联通块中只要剩下一个蓝色建筑即可(但必须有顺序地拆除,即离这个蓝色建筑的距离依次拆除,除故代码中用到了优先队列)。


找联通块自然用到BFS即可,而在BFS的过程中我们可以用step[i][j]记录(i,j)离联通块起点(即开始搜索的点)的距离。


然后就是拆除的过程了,上文说到用优先队列维护,根据step[i][j]的大小依次拆除并建造红色建筑,直到step[i][j]==1为止。如果不是这个顺序,则联通块断开,有的蓝色建筑就无法拆除,就不是最优解了。


具体细节见代码

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn= 505;
const ll mod = 1e9+7;
const int INF = 0x3f3f3f;
const double eps = 1e-6;

int n,m,cnt;
const int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int step[maxn][maxn];
char mp[maxn][maxn];

struct node
{
    int x,y;
}now,nex;

struct node2
{
    int op,x,y;
}ans[1000005];

struct node3
{
    int x,y,val;
    friend bool operator <(node3 a,node3 b)
    {
        return a.val<b.val;
    }
};

bool inbound(node a)
{
    return a.x>=1&&a.x<=n&&a.y>=1&&a.y<=m;
}

void bfs(int x,int y)
{
    queue<node>q;
    now.x=x;
    now.y=y;
    q.push(now);
    step[x][y]=1;
    while(q.size())
    {
        now=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            nex.x=now.x+dir[i][0];
            nex.y=now.y+dir[i][1];
            if(inbound(nex)&&mp[nex.x][nex.y]=='B'&&step[nex.x][nex.y]==0)
            {
                step[nex.x][nex.y]=step[now.x][now.y]+1;
                q.push(nex);
            }
        }
    }
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cnt=0;
        mst(step,0);
        for(int i=1;i<=n;i++)
        {
            scanf("%s",mp[i]+1);
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]=='.')
            {
                ans[cnt].x=i;
                ans[cnt].y=j;
                ans[cnt++].op=1;
                mp[i][j]='B';
            }
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]=='B'&&step[i][j]==0)
            {
                //printf("**i:%d j:%d\n",i,j);
                bfs(i,j);
            }
        }
        node3 temp;
        priority_queue<node3>q;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(mp[i][j]=='B')
            {
                temp.x=i;
                temp.y=j;
                temp.val=step[i][j];
                //printf("i:%d j:%d %d\n",i,j,step[i][j]);
                q.push(temp);
            }
        }
        while(q.size())
        {
            temp=q.top();
            q.pop();
            int xx=temp.x;
            int yy=temp.y;
            int val=temp.val;
            if(val!=1)
            {
                ans[cnt].x=xx;
                ans[cnt].y=yy;
                ans[cnt++].op=3;
                ans[cnt].x=xx;
                ans[cnt].y=yy;
                ans[cnt++].op=2;
            }
        }
        printf("%d\n",cnt);
        for(int i=0;i<cnt;i++)
        {
            if(ans[i].op==1) printf("B ");
            if(ans[i].op==2) printf("R ");
            if(ans[i].op==3) printf("D ");
            printf("%d %d\n",ans[i].x,ans[i].y);
        }
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值