[刷题笔记] 『MGOI』Simple Round I | C. 魔法禁林
Description
在一张无向简单连通图上,某人需要从\(s\)点走到\(t\)点,她初始有两个值,分别为魔力值,生命值,每条边上都有一个怪,假设她当前的魔力值为\(k\),怪的攻击力为\(w\)(输入数据已知),那么走到这里你会扣除\(\frac{w}{k}\)的生命值,同时,每做过一条边她的魔力值都会-1。她需要确保走到\(t\)时生命值和魔力值正好归零,且途中消耗的生命值最小。请求出这个最小值。
注意,你初始可以任意设置生命值和魔力值。
Solution
首先,每次都会扣除\(\frac{w}{k}\)的生命值,那么显然当\(k\geq w\)时她的生命值不会受影响,走这一步属于白走。我们又注意到\(w \leq 100\),那么显然我们在最优情况下最多走100步。
我们要求走到终点时生命值和魔力值都归零,初始可以任意设置生命值和魔力值,这看起来不好处理。但是走到终点要求归零呀,我们可以倒着处理,从终点走向起点,这样只需要求出到达起点时的最小生命值就好啦。这也算一种策略。
此时我想到了dp,看一下我们需要记录什么:
- 生命值
- 魔力值
- 走到哪个点
- 走了多少步
看一下如何记录呢?又可不可以优化呢?首先最小生命值时我们所求的,存在dp数组内即可。魔力值我们可以枚举,作为题目中的一个状态不能省略。走到哪个点作为dp数组的一个下标即可,是必须记录的。走了多少步同样也是必须记录的,因为若只记录走到哪个点若新走到了这个点所花步数少但是生命值比原来的多则也需要记录。我们进行状态转移的时候也是需要转移步数的。
由于魔力值每走一步就会-1,魔力值最多是100,所以我们这里就默认最多走100步。
这样我们就分析完了dp状态,接下来我们就可以写出dp方程啦!若设\(f_{i,j}\)为走到\(j\)号点花了\(i\)步,\(k,j\)为一条边,则满足:
\(f_{i,j}=min(f_{i,j},f_{i-1,k}+w\div i)\)
再考虑枚举顺序问题。
首先,通过观察状态转移方程,我们发现一次转移依赖于上一次的步数,所以需要优先保证,先枚举。此外,肯定要先枚举每个点,然后再对于每个点找到边啦!
再简单证明一下dp正确性(这一步非常重要,一个错误的dp可能不如暴力)
图上dp一般要考虑有无环,而本题没有规定没有环,所以我们需要考虑。
观察状态转移方程可以发现我们每次都在取min,而由于我们是倒着跑的所以对于新的节点我们都\(+w\div i\),所以若不断跑环则生命值会一次比一次高,由于取min这是不可能的,所以dp正确。
至此,本题得解。回顾一下本题有什么经验?首先,当正着跑图很困难时,且终点值唯一时,我们可以倒着跑图;其次,注意观察题目数据以及读题,例如本题我们就得出了最多走100步这一重要性质;最后,并不一定有环就不能dp,有环的时候注意验证dp正确性。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define INF 0x3f3f3f3f
#define N 10010
using namespace std;
const int MAXN = 2e4+10;
typedef pair<int,int> PAIR;
int n,m,s,t;
int f[1000][MAXN];
int ans = INF;
vector <PAIR> Edge[MAXN];
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
memset(f[0],INF,sizeof(f[0]));
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
Edge[u].push_back(PAIR(v,w));
Edge[v].push_back(PAIR(u,w));
}
f[0][t] = 0;//按照题意初始化
for(int i=1;i<=100;i++) //最多跑100步
{
memset(f[i],INF,sizeof(f[i1]));
for(int j=1;j<=n;j++)
{
for(auto x : Edge[j])
{
int v = x.first,w = x.second;
f[i][j] = min(f[i][j], f[i-1][v] + w / i);
}
}
ans = min(ans,f[i][s]);//每次取一下当魔力值为i也就是跑i步的时候最小生命值
}
cout<<ans<<endl;
return 0;
}
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17610409.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!