BZOJ 3875 Ahoi2014 骑士游戏 SPFA

题目大意:给定n个怪物,每个怪物可以用魔法直接干掉,或者用物理攻击使其分裂为一些其他怪物,求杀掉1号怪物的最小花销

令f[i]为杀死i号怪物的最小花销,则f[i]=min(k[i],s[i]+Σf[j]) 其中j为i用物理攻击后可以分裂为的怪物

但是直接DP有后效性,因此我们用SPFA来跑这个DP即可

注意如果每次更新一个点之后都重新计算花销会T掉

改成减掉花销的差值就好了 具体写法去看代码吧- -

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;

struct abcd{
	int to,next;
}table[2002002];
int head1[M],head2[M],tot;

int n,m;

long long f[M],g[M],phisical_attack[M],magic_attack[M];
//f[x]代表最小花销
//g[x]代表用物理攻击的最小花销
int q[M],r,h;
bool v[M];

void Add(int head[],int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}

void SPFA()
{
	int i;
	while(r!=h)
	{
		int x=q[(++h)%=M];v[x]=0;
		if(g[x]>=f[x])
			continue;
		for(i=head2[x];i;i=table[i].next)
		{
			if(!v[table[i].to])
				v[table[i].to]=true,q[(++r)%=M]=table[i].to;
			g[table[i].to]-=f[x];
			g[table[i].to]+=g[x];
		}
		f[x]=g[x];
	}
}

int main()
{
	int i,j,x;
	cin>>n;
	for(i=1;i<=n;i++)
	{
		#ifdef ONLINE_JUDGE
			scanf("%lld%lld",&phisical_attack[i],&magic_attack[i]);
		#else
			scanf("%I64d%I64d",&phisical_attack[i],&magic_attack[i]);
		#endif
		q[++r]=i;v[i]=true;
		scanf("%d",&m);
		for(j=1;j<=m;j++)
		{
			scanf("%d",&x);
			Add(head1,i,x);
			Add(head2,x,i);
		}
	}
	for(i=1;i<=n;i++)
	{
		f[i]=magic_attack[i];
		g[i]=phisical_attack[i];
		for(j=head1[i];j;j=table[j].next)
			g[i]+=magic_attack[table[j].to];
	}
	SPFA();
	cout<<f[1]<<endl;
	return 0;
}
时间: 2024-08-03 15:04:15

BZOJ 3875 Ahoi2014 骑士游戏 SPFA的相关文章

BZOJ 3875 Ahoi2014 骑士游戏

3875: [Ahoi2014]骑士游戏 Time Limit: 30 Sec  Memory Limit: 256 MB Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会 扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个

[BZOJ3875][AHOI2014]骑士游戏(松弛操作)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3875 分析: 类似于spfa求最短路,设d[i]表示完全消灭i号怪物的最小花费,我们对d[]进行动态更新 我们可以把问题反向:一开始所有怪物都存活,我们要找到一个怪物合成方案合成1号怪物,其中合成方法有两种,一种是魔法攻击逆向产生怪物,另一种就是由某个怪物的后继怪物合成此怪物 对于第一种产生方法的表示,令初始的d[i]=k[i]即可 对于第二种产生方法的表示,也就是算法的核心——类似

【BZOJ3875】【Ahoi2014】骑士游戏 SPFA处理有后效性动规

广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/44040735"); } 题解: 首先一个点可以分裂成多个新点,这样就有了图上动规的基础. 即f[i]表示i点被消灭的最小代价,它可以由分裂出的点们更新. 但是这个东西有后效性,所以我们用SPFA来处理它. spfa处理后效性动规 我

bzoj3875 [Ahoi2014]骑士游戏

Description [故事背景] 长期的宅男生活中,JYY又挖掘出了一款RPG游戏.在这个游戏中JYY会扮演一个英勇的骑士,用他手中的长剑去杀死入侵村庄的怪兽. [问题描述] 在这个游戏中,JYY一共有两种攻击方式,一种是普通攻击,一种是法术攻击.两种攻击方式都会消耗JYY一些体力.采用普通攻击进攻怪兽并不能把怪兽彻底杀死,怪兽的尸体可以变出其他一些新的怪兽,注意一个怪兽可能经过若干次普通攻击后变回一个或更多同样的怪兽:而采用法术攻击则可以彻底将一个怪兽杀死.当然了,一般来说,相比普通攻击,

【BZOJ3875】[Ahoi2014]骑士游戏【最短路】【DP】

[题目链接] 对于怪物u,普通攻击打死后产生的怪物为vi.设dis[u]表示打死u的最小花费,那么有 dis[u] = min{s[u] + ∑dis[vi], k[u]} 以这个为松弛条件,跑spfa就可以啦. 然而BZOJ跑了29s...变为倒数rank1 /* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> using namespace s

「AHOI2014/JSOI2014」骑士游戏

「AHOI2014/JSOI2014」骑士游戏 传送门 考虑 \(\text{DP}\). 设 \(dp_i\) 表示灭种(雾)一只编号为 \(i\) 的怪物的代价. 那么转移显然是: \[dp_i = \min(K_i, S_i + \sum_{j = 1}^{R_i} dp_{v_j})\] 但是我们会发现这个东西是有后效性的... 所以我们会想要用建图然后跑一个最短路什么的来搞... 于是我们观察到上面那个 \(\text{DP}\) 式子中,\(dp_i\) 如果用后面那一项来转移,显然

BZOJ 2756 奇怪的游戏(最大流)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2756 题意:在一个 N*M 的棋盘上玩,每个格子有一个数.每次 选择两个相邻的格子,并使这两个数都加上 1. 问最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1. 思路:对棋盘进行黑白染色,则每次操作使得黑白两色的格子总和各增加1.设黑色总和s1,个数cnt1:白色总和s2,个数cnt2,设最后的数字为x,那么有: x*cnt1-s1=x*cnt2-s2. (

BZOJ 1413 取石子游戏(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1413 题意:n堆石子排成一排.每次只能在两侧的两堆中选择一堆拿.至少拿一个.谁不能操作谁输. 思路:参考这里. int f1[N][N],f2[N][N],n,a[N]; void deal() { RD(n); int i,j,k; FOR1(i,n) RD(a[i]),f1[i][i]=f2[i][i]=a[i]; int p,q,x; for(k=2;k<=n;k++) for(

BZOJ 1978 取数游戏(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1978 题意:给出一个数列a,在其中找出下标依次增大的数,使得任意相邻的两个数的最大公约数大于等于m.找出最多的数字. 思路:f[i]表示前面的数字中最大公约数为i可以找出的最多的数字个数.那么对于当前数字x: 接着更新f: int f[N],a[N]; int n,m; int main() { RD(n,m); int i; FOR1(i,n) RD(a[i]); int j,k;