Loading

[AHOI2014/JSOI2014]骑士游戏

链接:https://www.luogu.com.cn/problem/P4042

题目描述:对于一个怪物\(i\),可以花费\(c_{i}\)的代价将其变为一个怪物集合,或花费\(c2_{i}\)的代价消灭他。求消灭怪物\(1\)的最小代价。

题解:由于这里涉及到了变化的传递,我们可以将原问题抽象为一个图,每一个点它可以花费\(c2_{i}\)的代价到达一个死亡节点或花费\(c_{i}\)的代价到达一个点集。

由于这个点集无法被直接表示,那么我们可以将他化为求点集的最小消灭代价之和\(+\)\(c_{i}\),直接消灭也就是可以将\(i\)的最小消灭代价化为\(c2_{i}\)

我们可以将\(dijkstra\)稍微改改,将所有点的\(dis\)初始化为\(c2_{i}\),每一次将转移变为求集的最小消灭代价之和\(+\)\(c_{i}\),也像\(dijkstra\)那样跑就行了。

#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
struct node
{
	long long v,nxt,data;
	bool vis;
};
node edge[2000001];
struct reads
{
	long long num,data;
	bool operator < (const reads &a)const
	{
		return data>a.data;
	}
};
long long dis[200001],dis2[200001];
int len,head[200001],n,in[200001],cnt[200001];
bool used[200001];
priority_queue<reads>q;
reads tmp;
reads make_reads(int x,long long y)
{
	tmp.num=x;
	tmp.data=y;
	return tmp;
}
void add(int x,int y,long long z)
{
	edge[++len].v=y;
	edge[len].data=z;
	edge[len].nxt=head[x];
	head[x]=len;
	return;
}
void dijkstra()
{
	int top;
	while (!q.empty())
	{
		top=q.top().num;
		q.pop();
		if (used[top])
			continue;
		used[top]=1;
		for (int i=head[top];i>0;i=edge[i].nxt)
		{
			if (!edge[i].vis&&cnt[edge[i].v]==in[edge[i].v]-1&&dis[edge[i].v]>dis2[edge[i].v]+dis[top]+edge[i].data)
			{
				edge[i].vis=1;
				cnt[edge[i].v]++;
				dis[edge[i].v]=dis2[edge[i].v]+dis[top]+edge[i].data;
				q.push(make_reads(edge[i].v,dis[edge[i].v]));
			}
			if (!edge[i].vis&&cnt[edge[i].v]<in[edge[i].v]-1)
			{
				edge[i].vis=1;
				cnt[edge[i].v]++;
				dis2[edge[i].v]=dis2[edge[i].v]+dis[top];
			}
		}
	}
	return;
}
int main()
{
	long long x,y,z,w;
	scanf("%lld",&n);
	for (int i=1;i<=n;++i)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		while (z--)
		{
			cin>>w;
			add(w,i,x);
			in[i]++;
		}
		dis[i]=y;
	}
	for (int i=1;i<=n;++i)
		q.push(make_reads(i,dis[i]));
	dijkstra(); 
	printf("%lld\n",dis[1]);
	return 0;
}
posted @ 2022-12-14 21:32  zhouhuanyi  阅读(37)  评论(0)    收藏  举报