题目链接:http://codeforces.com/contest/1105/problem/D
题目大意:
给一个地图,地图上有#(不可走),数字,和点组成,每种数字代表一种帮派。然后按照1-2-3.。。。。的顺序扩张领地,然后再1 2 3的扩张。每个帮派有一个扩张速度,直到最后无地可走,输出每个帮派各有多少领地。
思路:(读者可以从绿色字体开始往下读,前半部分为错误思路的分析)
起初我想的是可以用双端队列,把扩张速度可以看作扩张次数,然后如果双端队列的队首元素还有大于1的可扩张次数,就入队首,并且扩张次数减一,直到扩张次数为1,入队尾。这样做想法可行,但是实现的时候我们会发现一个尴尬的问题,后到一个点如果还有的扩张次数比原来的大,但是那个点已经被vis掉了怎么办??好解决。只要vis数组记录一下这个点的可扩张次数,如果这个点是“自己之前扩张的领地”且,可扩张次数比这个大,就再次入队。想法又可行了,但是超时在test20了。
这是怎么回事呢?比如这组样例
5 5 2
100 1
2.1.1
1.1.1
1.1.1
1.1.1
1.1.1
如果用的双端队列,那么我们从第一个1开始搜索,也就是(1,3)的位置。。搜索开始!!!(出队过程忽略不写)
1.(1,2)入队首(1,4)入队首,两个点的可扩张次数为99
2.(2,4)入队首.。。。(3,4)入队首。。。(等等!!为什么是(2,4)入队不是(2,2),要知道我们在不断地入队首,所以又不断地从队首取元素,所以双端队列的队首部分成为了一个栈!!!)
3. 。。。。直到(5,4)入队然后此处省略若干字。。(5,2)入队。。到目前为止我们只考虑了一个点,而这些走过的点在下边又会碰到更优的点(存在更近的源点)从而重复入队
所以双端队列+栈应该也可以过(纯粹口胡。)
#include
#include
#include
#include
#include
#include
#define ll long long
#include
using namespace std;
const int MAXN=1005;
int n,m,p;
char C[1005][1005];
int ans[20];
int vis[1005][1005];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
struct Point
{
int x,y,s,num;//x,y为坐标,s为扩张次数,num为帮派
Point(){}
Point(int x1,int y1,int s1,int num1){x=x1;y=y1;s=s1;num=num1;}
};
bool check(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m)return 1;
else return 0;
}
int sp[20];
vectorv[20];
void bfs()
{
queueq,q1;//q为每轮扩张的源点队列,q1为每个帮派每次扩长的辅助队列
for(int i=1;i<=p;i++){//用vector存第一次的地图上的扩张源点
int len=v[i].size();
for(int j=0;j1)q1.push(Point(xx,yy,now2.s-1,now2.num));
else q.push(Point(xx,yy,sp[now2.num],now2.num));
}
}
}
}
lun=now.num;
for(int i=0;i<4;i++){
int xx=now.x+dx[i];
int yy=now.y+dy[i];
if(check(xx,yy)&&!vis[xx][yy]){
vis[xx][yy]=1;
C[xx][yy]=now.num+'0';
if(now.s>1)q1.push(Point(xx,yy,now.s-1,now.num));
else q.push(Point(xx,yy,sp[now.num],now.num));
}
}
}
while(!q1.empty())//此时q空了,但是q1没空记得再清一次
{
Point now2=q1.front();
q1.pop();
for(int i=0;i<4;i++){
int xx=now2.x+dx[i];
int yy=now2.y+dy[i];
if(check(xx,yy)&&!vis[xx][yy]){
vis[xx][yy]=1;
C[xx][yy]=now2.num+'0';
if(now2.s>1)q1.push(Point(xx,yy,now2.s-1,now2.num));
else q.push(Point(xx,yy,sp[now2.num],now2.num));
}
}
}
}
int main()
{
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=p;i++)
scanf("%d",&sp[i]);
for(int i=1;i<=n;i++){
scanf("%s",C[i]+1);
for(int j=1;j<=m;j++){
if(C[i][j]!='.')vis[i][j]=1;
if(C[i][j]>='1'&&C[i][j]<='9'){
int now=C[i][j]-'0';
v[now].push_back(Point(i,j,sp[now],now));
}
}
}
bfs();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++){
if(C[i][j]>='0'&&C[i][j]<='9')ans[C[i][j]-'0']++;
// cout<