zcmu 1603 卡斯丁狗的战舰帝国(并查集+模拟)

思路:看到题目我只知道,普通的暴力模拟是不行的,但是不知道用什么办法优化,然后看到网上的大佬们用了并查集恍然大悟;

用并查集维护每条船攻击后的根节点,最后输出查询位置的根节点就行,如果在期间存在该位置的根节点的下个位置的根节点也已经沉了,说明所有的船都已经沉了,退出循环;

代码如下:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include<string>
#include <cmath>
#include<stack>
using namespace std;
int a[100050], b[100050];
int f[100050];
int find(int x)
{
	if (x == f[x])//说明已经是根节点了
		return x;
	else
		return f[x] = find(f[x]);//如果不是根节点,则找它的父节点
}

int main()
{
	int n, m;

	while (~scanf("%d%d",&n,&m))
	{
		for (int i = 1; i <=n; i++)
			scanf("%d", &a[i]);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &b[i]);
			f[i] = i;
		}
		int flag = 0;
		f[n+1] = 1;//*****************这步很重要!!!!******************把最后一条船后面的位置设置成1,说明这个位置指向对方的第一条船
		//用来满足条件中的:如果不存在,则攻击最远离 i 并且< i 没有死亡的敌方战舰。
		
		while(m--)
		{
			if (flag)
				break;
			for (int i = 1; i <= n; i++)
			{
				int t = find(i);
				a[t] -= b[i];

				if (a[t] <= 0)//如果i位上的根节点已经沉没了
				{
					int tt = find(t + 1);//找根节点的下个节点的根节点
					if (a[tt] <= 0)//说明该点的根节点已经沉了,说明战斗已经胜利
					{
						flag = 1;
						break;
					}
					else
					{
						f[t] = tt;//如果没有沉,说明战斗还没有结束,f[t]指向根节点
					}
				}
			}
		}
		int c;
		int i;
		scanf("%d", &c);
		while (c--)
		{

			scanf("%d", &i);
			
			if (flag)
				printf("win\n");
			else
				printf("%d\n", find(i));
		}
	}


	return 0;
}

 

点赞