P4822 [BJWC2012]冻结
题目链接
P4822 [BJWC2012]冻结
\(n\) 个点的稠密图。你可以进行 \(k\) 次操作,令某条边权值变成一半,每条边只能变换最多一次。询问从 \(1\) 到 \(n\) 的最短路。
\(
n \leq 50, k \leq 50 \text { 。 }
\)
解题思路
分层图
考虑将原本的 \(n\) 个点,\(m\) 条边的图复制 \(k+1\) 份,即 \(k+1\) 层,每层之间通过权值减半联系起来,即如果要求减半则往上一层,即如果第 \(i\) 层中存在 \(u,v\) 的边权值为 \(w\),\(i+1\) 中对应 \(u',v'\) 的边,则两层之间通过边 \(u,v'\) 和 \(v,u'\),权值为 \(w/2\) 联系起来,然后用最短路求解即可
时间复杂度:\(O(mklog(nk))\)
代码
// Problem: P4822 [BJWC2012]冻结
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4822
// Memory Limit: 125 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=55;
int n,m,k;
vector<PII> adj[N*N];
int res=0x3f3f3f3f,d[N*N];
bool v[N*N];
void dijkstra()
{
memset(d,0x3f,sizeof d);
d[1]=0;
priority_queue<PII,vector<PII>,greater<PII>> q;
q.push({0,1});
while(q.size())
{
auto t=q.top();
q.pop();
int x=t.se;
if(v[x])continue;
v[x]=true;
for(auto t:adj[x])
{
int y=t.fi,w=t.se;
if(d[y]>d[x]+w)
{
d[y]=d[x]+w;
q.push({d[y],y});
}
}
}
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
for(int j=0;j<=k;j++)
{
adj[x+j*n].pb({y+j*n,z}),adj[y+j*n].pb({x+j*n,z});
if(j<k)adj[x+j*n].pb({y+(j+1)*n,z>>1}),adj[y+j*n].pb({x+(j+1)*n,z>>1});
}
}
dijkstra();
for(int i=0;i<=k;i++)res=min(res,d[n+i*n]);
cout<<res;
return 0;
}