HDU 5336 XYZ and Drops (模拟+搜索,详解)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5336


题面:


XYZ and Drops

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 725    Accepted Submission(s): 201


Problem Description
XYZ is playing an interesting game called "drops". It is played on a rc grid. Each grid cell is either empty, or occupied by a waterdrop. Each waterdrop has a property "size". The waterdrop cracks when its size is larger than 4, and produces 4 small drops moving towards 4 different directions (up, down, left and right).

In every second, every small drop moves to the next cell of its direction. It is possible that multiple small drops can be at same cell, and they won't collide. Then for each cell occupied by a waterdrop, the waterdrop's size increases by the number of the small drops in this cell, and these small drops disappears.

You are given a game and a position ( x , y ), before the first second there is a waterdrop cracking at position ( x , y ). XYZ wants to know each waterdrop's status after T seconds, can you help him?

1r100 , 1c100 , 1n100 , 1T10000
 

Input
The first line contains four integers r , c , n and T . n stands for the numbers of waterdrops at the beginning.
Each line of the following n lines contains three integers xi , yi , sizei , meaning that the i -th waterdrop is at position ( xi , yi ) and its size is sizei . ( 1sizei4 )
The next line contains two integers x , y .

It is guaranteed that all the positions in the input are distinct.

Multiple test cases (about 100 cases), please read until EOF (End Of File).
 

Output
n lines. Each line contains two integers Ai , Bi :
If the i -th waterdrop cracks in T seconds, Ai=0 , Bi= the time when it cracked.
If the i -th waterdrop doesn't crack in T seconds, Ai=1 , Bi= its size after T seconds.
 

Sample Input
  
  
4 4 5 10 2 1 4 2 3 3 2 4 4 3 1 2 4 3 4 4 4
 

Sample Output
  
  
0 5 0 3 0 2 1 3 0 1
 

Author
XJZX
 

Source
 

解题:
    比赛的时候,卡在Walk out那题上了,看这道题又觉得题意不清晰,又怕超时,就没敢做,后面一个小时都在发呆,其实以后应该充分利用时间,不要太高估题目。往往最后一个小时才是最关键的。另外一只队伍最后一小时出了3题。
    题目意思是,在给定的方格中的某些位置,有一些水团,当新加入水珠时,如果该水团的体积大于4,那么它就会变成4个体积为1的水珠,朝上下左右四个方向去。每1秒移动1格,当新水珠加入水团时,水团可能会因体积大于4而爆炸。还有,如果多个水珠同时到达一个格子,而该格子没有水团,那么这些水珠将继续前行,如果出了边界,便消失。
    用bfs模拟水珠的运动,如果水珠加入一个水团,那么该水团的体积加一,并判断是否大于4,大于则分解成4个小水珠加入队列,并将该点体积清零。如果不大于,那么只是单纯的将体积加一,该水珠也就加入了水团,不再运动。同时需注意,因为可能一个水珠先到达水团,该水团就分解了,后续队列中又一水珠到达该处,如果之前分解的时候,不加标记,那么就会朝现在的水珠方向,多出一颗水珠,所以要加一个标记(用crack非零标记)。
    一个位置是不可能分解两次的,因为只有初始有水团的地方,才能吸收水珠,进而分解,所以也无需考虑crack是否会重复或覆盖的问题。

总结:
   要相信自己,基本上100人可以做的题目,那么都可以去尝试,也不用死抠复杂度,只要不是明显不可以的,而手头又空着,无题可做,那么就可以去大胆地敲。这题的模拟,其实比赛的时候觉得并不是很难,但因为过得只有100人,怕暴力模拟会超时,所以没做,事实证明46ms,实属遗憾啊!

代码:
#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
int r,c,n,t,tx,ty;
//四个方向
int d[4][2]={0,1,-1,0,0,-1,1,0};
//运动的小水珠的方向,坐标和时间
struct node
{
  int dir,x,y,t;
};
//判断是否在边界内
bool Inside(int x,int y)
{
	if(x>=1&&x<=r&&y>=1&&y<=c)
		return true;
	return false;
}
//存储水团的位置
struct drop
{
	int x,y;
}store[105];
queue <node> qe;
//map记容量
int  map[105][105];
//crack记分解时间
int crack[105][105];
//模拟水珠运动
void bfs()
{
	int dir,ti,xx,yy;
	node tmp;
	while(!qe.empty())
	{
		//取当前节点
		tmp=qe.front();
		qe.pop();
		tx=tmp.x;
		ty=tmp.y;
		dir=tmp.dir;
		ti=tmp.t;
		//如果该点有水团
		if(map[tx][ty])
		{
			//体积加1
			map[tx][ty]++;
			//大于4,分解
			if(map[tx][ty]>4)
			{
				//记录分解时间
				crack[tx][ty]=ti;
				map[tx][ty]=0;
                for(int i=0;i<4;i++)
	            {
				 //四个方向
				 xx=tx+d[i][0];
		         yy=ty+d[i][1];
				 //在边界内
		         if(Inside(xx,yy))
		         {
                   tmp.x=xx;
			       tmp.y=yy;
			       tmp.t=ti+1;
			       tmp.dir=i;
				   //在时间T内
				   if(tmp.t<=t)
			       qe.push(tmp);
				 }
		        }
	         }
		}
		//该点原本就没有水团或者水团已经分解,但不是刚刚分解的,去除那个已经弹出的水珠的情况
		else if(crack[tx][ty]!=ti)
		{
            xx=tx+d[dir][0];
			yy=ty+d[dir][1];
			if(Inside(xx,yy))
			{
				tmp.x=xx;
				tmp.y=yy;
				tmp.t=ti+1;
				tmp.dir=dir;
				if(tmp.t<=t)
				qe.push(tmp);
			}
		}
	}
}
int main()
{
	int x,y,v;
	node tmp;
	while(~scanf("%d%d%d%d",&r,&c,&n,&t))
	{
       memset(map,0,sizeof(map));
	   memset(crack,0,sizeof(crack));
	   //读入
       for(int i=0;i<n;i++)
	   {
		   scanf("%d%d%d",&store[i].x,&store[i].y,&v);
		   map[store[i].x][store[i].y]=v;
	   }
	   scanf("%d%d",&x,&y);
	   //初始点分解
	   for(int i=0;i<4;i++)
	   {
          tx=x+d[i][0];
		  ty=y+d[i][1];
		  if(Inside(tx,ty))
		  {
            tmp.x=tx;
			tmp.y=ty;
			tmp.t=1;
			tmp.dir=i;
			qe.push(tmp);
		  }
	   }
	   //模拟
	   bfs();
	   //输出
	   for(int i=0;i<n;i++)
	   {
         if(crack[store[i].x][store[i].y])
			 printf("0 %d\n",crack[store[i].x][store[i].y]);
		 else
			 printf("1 %d\n",map[store[i].x][store[i].y]);
	   }
	} 
	return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值