1 条题解
-
0
自动搬运
来自洛谷,原作者为

WorldMachine
请引领我至夜晚熠熠闪烁的群星之下搬运于
2025-08-24 22:57:04,当前版本为作者最后更新于2024-04-30 18:19:58,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
模拟赛出了这题,我是这样趋势的:
- 打了状压 DP 之后过了大样例;
- 旁边的大佬说会有重边,于是判了重边;
- 但是我没保存文件……哈哈
言归正传,这题还是比较简单的,只要注意到 这神奇的数据范围,然后就很容易想到 的状压 DP 做法:首先,对于每个受灾点,处理出每个点是否可能在它到 的最短路上,然后状压所有状态即可:对于每个状态,枚举每个可以建立救助站的点,看这个点在哪些点的最短路图中(不用真正地建图),然后答案就是去掉这些被覆盖点后状态的答案 。
#include <bits/stdc++.h> using namespace std; #define pb emplace_back typedef long long ll; const int N = 205, M = 10005; int n, m, k, v2[N], dp[1048580]; bool v1[N]; ll dis[N][N]; int G1[N]; int main() { scanf("%d%d%d", &n, &m, &k); for (int i = 1, x; i <= n; i++) scanf("%d", &x), v1[i] = x; for (int i = 1, x; i <= k; i++) scanf("%d", &x), v2[i] = x; memset(dis, 0x3f, sizeof(dis)); for (int i = 1, u, v, w; i <= m; i++) { scanf("%d%d%d", &u, &v, &w); dis[u][v] = min(dis[u][v], (ll)w); dis[v][u] = min(dis[v][u], (ll)w); } for (int i = 1; i <= n; i++) dis[i][i] = 0; for (int k = 1; k <= n; k++) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); } } for (int i = 1; i <= k; i++) { for (int j = 1; j <= n; j++) G1[j] |= ((dis[v2[i]][1] == dis[v2[i]][j] + dis[j][1]) << i - 1); } memset(dp, 0x3f, sizeof(dp)); dp[0] = 0; for (int c = 1; c < (1 << k); c++) { for (int i = 1; i <= n; i++) { if (!v1[i]) continue; dp[c] = min(dp[c], dp[c ^ (G1[i] & c)] + 1); } } printf("%d\n", dp[(1 << k) - 1]); }
- 1
信息
- ID
- 10034
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者