Magic
题目#
由于没找到原题, 只能挂上 pdf
题目下载
算法#
暴力#
标准的 dp + 图论(可是考前并没有听说过)
于是推出式子
定义
转移时显然只能从出边中找, 并且由于不是 DAG, 需要想办法收敛状态
于是想到 spfa 跑一遍 (不知道这种情况下 spfa 是死是活, 疑似有利用 dp 单调性的更优算法)
平均时间复杂度
正解#
挂个 pdf
题解下载
想到之前一个同学, 遂下定决心 A 了这道题
终点一定, 大概要倒着推 dp
问题在于边权实在不好表示
因为边权只与起点到这个点的
定义
枚举
枚举
能把时间复杂度优化到平均
感兴趣可以把我的 spfa 卡了, 让我开开眼
代码#
暴力#
#include <bits/stdc++.h>
#define int long long
const int MAXM = 2024;
const int MAXN = 1024;
const int INF = INT_MAX;
int n, m;
struct edge
{
int to;
int w;
int nxt;
} Edge[MAXM << 1]; //
int head[MAXN];
int cnt = 0;
void init()
{
for (int i = 1; i <= n; i++)
{
head[i] = -1;
}
}
void addedge(int u, int v, int w)
{
Edge[++cnt].to = v;
Edge[cnt].w = w;
Edge[cnt].nxt = head[u];
head[u] = cnt;
}
int Q;
bool inq[MAXN][520];
int dp[MAXN][520]; //这题真能用来表白了吧..
struct node
{
int Point;
int Gcd;
};
std::queue<node> CanRelax;
void spfa(int from)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= 500; j++)
{
dp[i][j] = INF;
}
}
memset(inq, false, sizeof(inq));
for (int i = 1; i <= 500; i++)
{
dp[from][i] = 0;
CanRelax.push((node){from, i});
inq[from][i] = true;
}
while(!CanRelax.empty())
{
node Now = CanRelax.front();
CanRelax.pop();
inq[Now.Point][Now.Gcd] = false;
for (int i = head[Now.Point]; ~i; i = Edge[i].nxt)
{
int Nowto = Edge[i].to;
int Noww = Edge[i].w;
if(Noww % std::__gcd(Now.Gcd, Noww))
continue;
if (dp[Now.Point][Now.Gcd] + Noww / std::__gcd(Now.Gcd, Noww) < dp[Nowto][std::__gcd(Now.Gcd, Noww)])
{
dp[Nowto][std::__gcd(Now.Gcd, Noww)] = dp[Now.Point][Now.Gcd] + Noww / std::__gcd(Now.Gcd, Noww);
if (!inq[Nowto][std::__gcd(Now.Gcd, Noww)])
{
inq[Nowto][std::__gcd(Now.Gcd, Noww)] = true;
CanRelax.push((node){Nowto, std::__gcd(Now.Gcd, Noww)});
}
}
}
}
}
signed main()
{
scanf("%lld %lld", &n, &m);
init();
for (int i = 1; i <= m; i++)
{
int u, v, w;
scanf("%lld %lld %lld", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
scanf("%lld", &Q);
while(Q--)
{
int Begin;
scanf("%lld", &Begin);
spfa(Begin);
int Ans = INF;
for (int j = 1; j <= 500; j++)
{
Ans = std::min(Ans, dp[n][j]);
}
printf("%lld\n", Ans);
}
return 0;
}
/*
4 3
1 2 2
2 3 4
3 4 6
3
1
2
3
6
4
1
I
Love
You
*/
/*
10 20
3 4 34
1 5 97
4 1 85
7 8 81
6 1 23
8 3 57
5 2 77
9 1 68
10 3 95
2 10 68
8 5 21
6 8 68
5 7 34
2 8 91
2 7 37
3 7 68
2 9 68
8 4 68
5 10 68
2 8 68
7
1
7
4
6
3
9
5
3
3
3
3
1
2
1
*/
正解#
#include <bits/stdc++.h>
#define int long long
const int MAXM = 2024;
const int MAXN = 1024;
const int INF = INT_MAX;
#define lcm(x, y) x / std::__gcd(x, y) * y
int n, m;
struct edge
{
int to;
int w;
int nxt;
} Edge[MAXM << 1]; //
int head[MAXN];
int cnt = 0;
void init()
{
for (int i = 1; i <= n; i++)
{
head[i] = -1;
}
}
void addedge(int u, int v, int w)
{
Edge[++cnt].to = v;
Edge[cnt].w = w;
Edge[cnt].nxt = head[u];
head[u] = cnt;
}
int Q;
bool inq[MAXN][520];
int dp[MAXN][520]; //
struct node
{
int Point;
int Gcd;
};
std::queue<node> CanRelax;
int ans[MAXN]; // 存储每一个点的答案
void spfa()
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= 500; j++)
{
dp[i][j] = INF;
}
}
memset(inq, false, sizeof(inq));
for (int i = 1; i <= 500; i++)
{
dp[n][i] = 0;
CanRelax.push((node){n, i});
inq[n][i] = true;
}
for (int i = 1; i <= n; i++)
{
ans[i] = INF;
}
ans[n] = 0;
while (!CanRelax.empty())
{
node Now = CanRelax.front();
CanRelax.pop();
inq[Now.Point][Now.Gcd] = false;
ans[Now.Point] = std::min(ans[Now.Point], dp[Now.Point][Now.Gcd]);
for (int i = head[Now.Point]; ~i; i = Edge[i].nxt)
{
int Nowto = Edge[i].to;
int Noww = Edge[i].w;
if (Noww % Now.Gcd || Nowto == n) // 这里记得防爆炸
continue;
for (int j = 1; j * Now.Gcd <= 500; j++)
{
if (dp[Nowto][j * Now.Gcd] > dp[Now.Point][Now.Gcd] + Noww / Now.Gcd) // 逆向顺序
{
dp[Nowto][j * Now.Gcd] = dp[Now.Point][Now.Gcd] + Noww / Now.Gcd;
if (!inq[Nowto][j * Now.Gcd])
{
inq[Nowto][j * Now.Gcd] = true;
CanRelax.push((node){Nowto, j * Now.Gcd});
}
}
}
}
}
}
signed main()
{
scanf("%lld %lld", &n, &m);
init();
for (int i = 1; i <= m; i++)
{
int u, v, w;
scanf("%lld %lld %lld", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
scanf("%lld", &Q);
spfa();
while (Q--)
{
int Begin;
scanf("%lld", &Begin);
printf("%lld\n", ans[Begin]);
}
return 0;
}
/*
4 3
1 2 2
2 3 4
3 4 6
3
1
2
3
6
4
1
I
Love
You
*/
/*
10 20
3 4 34
1 5 97
4 1 85
7 8 81
6 1 23
8 3 57
5 2 77
9 1 68
10 3 95
2 10 68
8 5 21
6 8 68
5 7 34
2 8 91
2 7 37
3 7 68
2 9 68
8 4 68
5 10 68
2 8 68
7
1
7
4
6
3
9
5
3
3
3
3
1
2
1
*/
总结#
一类套路题
之前居然没见过
有依赖性的 dp 必须吧每一维都开好
多观察题面
终点 / 起点 一定的题目都可以有特殊优化
小知识
胡扯#
感谢样例输出让我 A 了这题
分类:
题目总结 / dp / 图上dp
, 题目总结 / 图论
vivo 50
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】