「JSOI2010」旅行

传送门

比较妙的一道 \(\text{DP}\) 题,思维瓶颈应该就是如何确定状态。

首先将边按边权排序。

如果我们用 \(01\) 串来表示 \(m\) 条边是否在路径上,那么我们就可以通过钦定前 \(x\) 条边在路径上来确定目标状态。

其中有的边消耗了魔法使用次数,有的没消耗。

那么我们就可以设 \(dp[i][j][k]\) 表示到点 \(i\) ,经过了前 \(j\) 条被钦定边,并且使用了 \(k\) 次魔法的最短路,那么转移就是(假设我们现在要从点 \(u\) 走到点 \(v\)):

如果当前这条边是被钦定的边:\(dp_{u, j, k} + w_{j + 1} \to dp_{v, j + 1, k}\)

如果当前这条边不是被钦定的边:

  • 用魔法:\(dp_{u, j, k} + w_{j + 1} \to dp_{v, j + 1, k + 1}\)
  • 不用魔法:\(dp_{u, j, k} + dis(u, v) \to dp_{v, j, k}\)

参考代码:

#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} const int _ = 52, __ = 152; int n, m, k, ans = 2147483647; vector < int > vec[_]; struct node { int u[2], w; } p[__];
inline bool cmp(const node& x, const node& y) { return x.w < y.w; } struct DP { int i, j, k; } ; inline void calc(int x) {
static queue < DP > Q;
static int exi[_][__][_], dp[_][__][_];
memset(dp, 0x3f, sizeof dp);
dp[1][0][0] = 0, Q.push((DP) { 1, 0, 0 });
while (!Q.empty()) {
DP u = Q.front(); Q.pop(), exi[u.i][u.j][u.k] = 0;
for (rg int i = 0; i < vec[u.i].size(); ++i) {
int id = vec[u.i][i], v = p[id].u[u.i == p[id].u[0]];
if (id <= x) {
if (dp[v][u.j + 1][u.k] > dp[u.i][u.j][u.k] + p[u.j + 1].w && u.j < x) {
dp[v][u.j + 1][u.k] = dp[u.i][u.j][u.k] + p[u.j + 1].w;
if (!exi[v][u.j + 1][u.k]) exi[v][u.j + 1][u.k] = 1, Q.push((DP) { v, u.j + 1, u.k });
}
} else {
if (dp[v][u.j + 1][u.k + 1] > dp[u.i][u.j][u.k] + p[u.j + 1].w && u.j < x && u.k < k) {
dp[v][u.j + 1][u.k + 1] = dp[u.i][u.j][u.k] + p[u.j + 1].w;
if (!exi[v][u.j + 1][u.k + 1]) exi[v][u.j + 1][u.k + 1] = 1, Q.push((DP) { v, u.j + 1, u.k + 1 });
}
if (dp[v][u.j][u.k] > dp[u.i][u.j][u.k] + p[id].w) {
dp[v][u.j][u.k] = dp[u.i][u.j][u.k] + p[id].w;
if (!exi[v][u.j][u.k]) exi[v][u.j][u.k] = 1, Q.push((DP) { v, u.j, u.k });
}
}
}
}
for (rg int i = 0; i <= k; ++i) ans = min(ans, dp[n][x][i]);
} int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n), read(m), read(k);
for (rg int u, v, w, i = 1; i <= m; ++i) read(u), read(v), read(w), p[i] = (node) { u, v, w };
sort(p + 1, p + m + 1, cmp);
for (rg int i = 1; i <= m; ++i) vec[p[i].u[0]].push_back(i), vec[p[i].u[1]].push_back(i);
for (rg int i = 0; i <= m; ++i) calc(i);
printf("%d\n", ans);
return 0;
}

「JSOI2010」旅行的更多相关文章

  1. 「JSOI2013」旅行时的困惑

    「JSOI2013」旅行时的困惑 传送门 由于我们的图不仅是一个 \(\text{DAG}\) 而且在形态上还是一棵树,也就是说我们为了实现节点之间互相可达,就必须把每条边都覆盖一次,因为两个点之间的 ...

  2. 「JSOI2010」排名

    「JSOI2010」排名 传送门 看到先后顺序限制和字典序,很容易想到拓扑排序 + 贪心. 考虑具体做法: 对于第一问: 我们开一个大根堆来代替队列,然后从大到小构造出各个元素的排名. 我们连边 \( ...

  3. 「JSOI2010」挖宝藏

    「JSOI2010」挖宝藏 传送门 由于题目中说道挖一个位置的前提是挖掉它上面的三个,以此类推可以发现,挖掉一个点就需要挖掉这个点往上的整个倒三角,那么也就会映射到 \(x\) 轴上的一段区间(可以发 ...

  4. 「JSOI2010」找零钱的洁癖

    「JSOI2010」找零钱的洁癖 传送门 个人感觉很鬼的一道题... 首先我们观察到不同的数最多 \(50\) 个,于是考虑爆搜. 但是这样显然不太对啊,状态数太多了. 然后便出现了玄学操作: \(\ ...

  5. 「SDOI2014」旅行(信息学奥赛一本通 1564)(洛谷 3313)

    题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我 ...

  6. LG4171/BZOJ1823 「JSOI2010」满汉全席 2-SAT

    问题描述 LG4171 BZOJ1823 题解 显然,每个评委对每个材料的满式/汉式要求是对\(n\)个元素的\(0,1\)取值限制. 显然想到\(\mathrm{2-SAT}\) 于是就可以切掉了. ...

  7. 「BZOJ2388」旅行规划

    传送门 分块+凸包 求出前缀和数组s 对于l~r加上k,相当于s[l]~s[r]加上一个首项为k,公差为k的等差数列.r~n加上k*(r-l+1). 分块之后对每一块维护两个标记,一个记录它加的等差数 ...

  8. 「JSOI2010」满汉全席

    前言 由于蒟蒻才刚开始学 \(\text{2-SAT}\),所以题解中有的地方可能不够精炼,望多包涵! 题目描述 题目意思很简单,标准的\(\text{2-SAT}\)问题模型.那么我们就先来介绍一下 ...

  9. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

随机推荐

  1. Multisim 如何调整编辑界面大小

    1.option -> sheet properties 2.选择workspace

  2. 关于Spring+mybatis使用@Transactional注解事物没有生效的问题

    控制台日志信息: was not registered for synchronization because synchronization is not active JDBC Connectio ...

  3. 7-8 Left-pad

    思路 注意读入和输出格式 如果用fgets读入的话会带上回车,输出的时候一定不要输出了双回车 并且此时的length也会比原始长度多了一,要注意长度比较,这里容易出错 代码 #include < ...

  4. 【visio】故障树分析图

    率属于 商务 故障树是从一个可能的事故开始,自上而下.一层层的寻找顶事件的直接原因和间接原因事件,直到基本原因事件,并用逻辑图把这些事件之间的逻辑关系表达出来. 主要的应用场景:分析复杂问题原因,一个 ...

  5. [单片机] ESP8266 开机自动透传

    AT+CWMODE=1//设置WiFi工作在透传模式 AT+CWJAP_DEF="XX","YYY"//设置要链接的wifi名称.密码,并进行连接 //设置TC ...

  6. Codeforces Round #618 (Div. 1)C(贪心)

    把所有数看作N块,后面的块比前面的块小的话就合并,这个过程可能会有很多次,因为后面合并后会把前面的块均摊地更小,可能会影响更前面地块,像是多米诺骨牌效应,从后向前推 #define HAVE_STRU ...

  7. python的logging库

    logging库 简介 logging库提供日志打印功能. 值得一提的是,不仅能打印到日志文件,还能打印到控制台. 日志级别 logging一共分为5个级别,从低到高依次为:  DEBUG<IN ...

  8. 数据提取之JSON与JsonPATH

    数据提取之JSON与JsonPATH JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写.同时也方便了机器进行解析和生成.适 ...

  9. 移动端 vue + mintUI 实现头部页签切换,按需加载~

    记录~记录~~有时候,我们会遇到一个页面有两个页签切换需求,但是为了避免同时加载两个页面,我们要做到的就是当前进入的是那个页面,就先加载哪一个页面,并且也不会造成浏览器地址的变化.一开始我使用的方法是 ...

  10. 谈谈对Spring IOC的理解(转载)

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的,今天和大家 ...