题目描述:
Kilani and the Game
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Kilani is playing a game with his friends. This game can be represented as a grid of size n×m
, where each cell is either empty or blocked, and every player has one or more castles in some cells (there are no two castles in one cell).
The game is played in rounds. In each round players expand turn by turn: firstly, the first player expands, then the second player expands and so on. The expansion happens as follows: for each castle the player owns now, he tries to expand into the empty cells nearby. The player i
can expand from a cell with his castle to the empty cell if it's possible to reach it in at most (where s**i
Input
The first line contains three integers n, and p, 1≤p≤9
The second line contains p integers (1≤s≤109
The following n lines describe the game grid. Each of them consists of symbols, where '' denotes an empty cell, '' denotes a blocked cell and digit x) denotes the castle owned by player x
Output
Print p integers — the number of cells controlled by each player after the game ends.
Examples
Input
Copy
3 3 2
1 1
1..
...
..2
Output
Copy
6 3
Input
Copy
3 4 4
1 1 1 1
....
#...
1234
Output
Copy
1 4 3 3
Note
The picture below show the game before it started, the game after the first round and game after the second round in the first example:
In the second example, the first player is "blocked" so he will not capture new cells for the entire game. All other player will expand up during the first two rounds and in the third round only the second player will move to the left.
思路:
题目就是几个人玩游戏,拓展领地的游戏,每个人有一个最多移动步数,也就是从现有领地向外拓展的最大步数,一个人一个人拓展自己的领地,直到没有地方可拓展时游戏结束,输出每个人的领地大小。
刚开始时我用的DFS模拟,循环每个人,对每个人来说拓展自己的现有的且处于边界状态的格子。但是在十五个测试点的地方WA了,现在不知道是哪里写的不对。
然后改用BFS,维护一个向量,向量里的元素就是每个人的访问队列。每次访问过后,把边界状态(即步数用完的状态重新压入队列。用一个大循环,在其中这样模拟每个回合,一直下去直到所有玩家的访问后的边界状态的队列为空,也就是不会进行拓展时推出大循环。这里判断所有玩家是否均不可拓展有一点小trick,用一个标记flag(初始为0)记录是否退出大循环,另一个标记flag1(初始为一)记录每个玩家的可访问队列是否为空,为空置为0,每一个回合不断flag|=flag1,如果所有玩家不可拓展,即每个flag1=0,那么flag=0,这时候就可以退出大循环,游戏结束了。
注意的是刚开始我是直接修改原地图,最后扫一遍原地图做统计,但会超时好像(超了十几次,┓(;´_`)┏),因为每个点(除了每次出队的边界点)只能出队一次,出队且不为边界点的情况下统计即可,因为边界点到最后也会变成非边界点。
代码:
#include <iostream>
#include <vector>
#include <queue>
#include <memory.h>
#include <cstdio>
#define max_n 1005
using namespace std;
int n,m,p;
struct point
{
int x;
int y;
int v;
};
vector<queue<point> > vec;
int speed[10];
char G[max_n][max_n];
int cnt[10];
int dirx[4] = {0,-1,0,1};
int diry[4] = {-1,0,1,0};
inline void extend(int x,int y,int id,int v)
{
//cout << "x " << x << " y " << y << " id " << id << " v " << v << endl;
for(int i = 0;i<4;i++)
{
int xx = x+dirx[i];
int yy = y+diry[i];
if(xx<0||xx>=n||yy<0||yy>=m||G[xx][yy]!='.')
{
continue;
}
else
{
char ch = id+'0';
G[xx][yy] = ch;
//cnt[id]++;
point p;
p.x = x+dirx[i];
p.y = y+diry[i];
p.v = v-1;
vec[id].push(p);
}
}
}
#pragma optimize(3)
int main()
{
cin >> n >> m >> p;
queue<point> que;
vec.push_back(que);
for(int i = 1;i<=p;i++)
{
cin >> speed[i];
queue<point> que;
vec.push_back(que);
}
for(int i = 0;i<n;i++)
{
for(int j = 0;j<m;j++)
{
cin >> G[i][j];
if('1'<=G[i][j]&&G[i][j]<='9')
{
point p;
p.x = i;
p.y = j;
p.v = speed[G[i][j]-'0'];
vec[G[i][j]-'0'].push(p);
}
}
}
int flag;
queue<point> que2;
while(1)
{
flag = 0;
//cout << flag << endl;
for(int i = 1; i<=p; i++)
{
int flag1 = 1;
while(!vec[i].empty())
{
point p = vec[i].front();
vec[i].pop();
if(p.v==0)
{
p.v = speed[i];
que2.push(p);
continue;
}
int x = p.x;
int y = p.y;
int v = p.v;
cnt[i]++;
extend(x,y,i,v);
}
if(que2.empty())
{
flag1 = 0;
}
while(!que2.empty())
{
point p = que2.front();
que2.pop();
vec[i].push(p);
}
/*for(int j = 0; j<n; j++)
{
for(int k = 0; k<m; k++)
{
cout << G[j][k] << " ";
}
cout << endl;
}
cout << endl;*/
flag|=flag1;
}
if(flag==0)
{
break;
}
}
for(int i = 1;i<=p;i++)
{
cout << cnt[i] << " ";
}
cout << endl;
return 0;
}