水杯 (数据结构作业)

版权声明:未经本人同意,禁止转载。 https://blog.csdn.net/qq_34022601/article/details/84187852

算法与数据结构实验题 12.2  水杯

 

★实验任务

 

有 n 个水杯如图所示放置

从上到下,编号由 1 开始一直到 n,容量 ai 也依次增大(ai+1 > ai),如果

i 号杯子存的水超过了它的容量,则会像 i+1 号水杯流,以此类推现在给你两个操作

操作一: 1 x y 给 x 号杯子加 y 容量的水操作二: 2 x 查询 x 杯子里有多少水。

★数据输入

输入第一行为一个正整数 n

接下来 n 个元素,表示第 i 个水杯的容量接着输入操作的个数 q

接下来 q 行操作。

60%的数据 1<=n<=100,1<=ai,y<=100.

100%的数据 1<=n<=100000,1<=ai,y<=1000000000.

★数据输出

对于每个操作二,输出对应的值。

 

输入示例

输出示例

2

4

5 10

5

6

8

1 1 4

 

2 1

 

1 2 5

 

1 1 4

 

2 1

 

2 2

 

 

乍一看,暴力遍历,能过九个点。

仔细一想,我们多遍历了许多已经装满水的水杯,把这些水杯拿走就行了(拿不拿走对结果没影响,已经满了的水杯,浇了水,也会往下流。不如直接把它拿走)

这是是个并查集,分为两个集合,浇满水的集合和未浇满的集合。我们统计未浇满的集合就行了,浇满的做个标记就行了。不停地按顺序把浇满的位置退出未浇满的集合。

#include <cstdio> 
#include <set>
using namespace std;
int cup[100100]={0}; 	// 容量集合 
int a[100100];			//记录每个水杯当前的水的体积 
int main()
{
	set <int> s;
	int n,q,x,y,t;
	scanf ("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf ("%d",&a[i]);
		s.insert(i);
	}
	scanf ("%d",&q);
	set <int> ::iterator it;
	set <int> ::iterator temp;
	while(q--)
	{
		scanf ("%d %d",&t,&x);
		if (t==1)
		{
			it=s.lower_bound(x);//查找水杯 
			scanf ("%d",&y);
			while(y>0&&it!=s.end())
			{
				cup[*it]+=y;
				if (cup[*it]>a[*it])
				{
					y=cup[*it]-a[*it];
					cup[*it]=a[*it];
					temp=it;
					temp++;
					s.erase(it);	//删除这个水杯 
					it=temp;	
				}
				else
					y=0;
			}
		}
		else
		{
			printf ("%d\n",cup[x]);
		}	
	}
	return 0;
}

在来一个标准并查集

#include <cstdio>
#include <cstring>
using namespace std;
int a[1000100];			//容量a 
int s[1000100];			//父亲数组 	集合的根节点时当前节点往后第一个未浇满的节点 
int cup[1000100];		//实际容量 
void Make_Set(void)		//初始化 
{
	memset(s,-1,sizeof(s));
}
int Find(int x)			//查找 
{
	if (s[x]<=0)
		return x;
	else
		return (s[x]=Find(s[x]));
}
void Union(int root1,int root2)		//合并
{
	root1=Find(s[root1]);
	root2=Find(s[root2]);
	if (root1==root2)
		return ;
	if (s[root1]<s[root2])
		s[root2]=root1;
	else
	{
		if (s[root1]==s[root2])
			s[root2]--;
		s[root1]=root2;
	}
}
void Plant(int x,int y,int n)	//浇水 
{
	int i=Find(x);
	while (y>0&&i!=n+1)	//浇到地上 || 水浇完了  ,停止循环 
	{
		cup[i]+=y;
		if (cup[i]>a[i])
		{
			y=cup[i]-a[i];
			cup[i]=a[i];
			Union(i,i+1); 
			i=Find(i+1);
		}
		else
			y=0;
	}
}
int main()
{
	int x,y,n,q,t;
	scanf ("%d",&n);
	for (int i=1;i<=n;i++)
		scanf ("%d",&a[i]);
	scanf ("%d",&q);
	while (q--)
	{
		scanf ("%d %d",&t,&x);
		if (t==1)
		{
			scanf ("%d",&y);
			Plant(x,y,n);
		}
		else
		{
			printf ("%d\n",cup[x]);
		}
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_34022601/article/details/84187852