链接: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;
}
标签:JSOI2014,int,AHOI2014,long,edge,骑士,data,top,dis
From: https://www.cnblogs.com/zhouhuanyi/p/16983654.html