[JSOI2010]旅行
链接:https://www.luogu.com.cn/problem/P6029
题目描述:给定一个\(n\)个\(m\)条边的无向图,可以交换\(k\)组边,求\(1\)到\(n\)的最短路。
题解:发现值域都比较小,考虑\(dp\)。
我们可以发现,存在一个段点\(L\),使得前\(L\)条边只换不走,后面的\(m-L\)条边换为前\(L\)条边,这样走一定不会使答案更差。
令\(dp_{i,j,k}\)表示到节点\(i\),在前\(L\)条边中选了\(j\)条边,轮换了\(k\)次的最短路。
则有:
当前边在前\(L\)条边时:
\(dp_{i,j,k}+edge_{j+1}->dp_{v,j+1,k}\)
当前边不在前\(L\)条边时:
\(dp_{i,j,k}+edge_{now}->dp_{v,j,k}\)
\(dp_{i,j,k}+edge_{j+1}->dp_{v,j,k+1}\)
转移可以建分层图跑最短路。
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
struct node
{
int v,nxt,data;
};
struct edg
{
int u,v,data;
bool operator < (const edg &a)const
{
return data<a.data;
}
};
struct reads
{
int num,data;
bool operator < (const reads &a)const
{
return data>a.data;
}
};
node edge[2000001];
edg edges[1000001];
int n,m,k,head[1000001],dis[1000001],len;
bool used[1000001];
void add(int x,int y,int z)
{
edge[++len].v=y;
edge[len].data=z;
edge[len].nxt=head[x];
head[x]=len;
return;
}
int d(int x,int y,int z)
{
return (x-1)*(k+1)*(m+1)+y*(m+1)+z+1;
}
reads tmp;
reads make_reads(int x,int y)
{
tmp.num=x;
tmp.data=y;
return tmp;
}
priority_queue<reads>q;
void dijkstra()
{
int top;
for (int i=1;i<=d(n,k,m);++i)
{
dis[i]=1e9;
used[i]=0;
}
q.push(make_reads(1,0));
dis[1]=0;
while (!q.empty())
{
top=q.top().num;
q.pop();
if (used[top])
continue;
used[top]=1;
for (int i=head[top];i>0;i=edge[i].nxt)
if (dis[edge[i].v]>dis[top]+edge[i].data)
{
dis[edge[i].v]=dis[top]+edge[i].data;
q.push(make_reads(edge[i].v,dis[edge[i].v]));
}
}
return;
}
int main()
{
int x,y,ans=1e9;
cin>>n>>m>>k;
for (int i=1;i<=m;++i)
cin>>edges[i].u>>edges[i].v>>edges[i].data;
sort(edges+1,edges+m+1);
for (int L=0;L<=m;++L)
{
len=0;
for (int i=1;i<=d(n,k,m);++i)
head[i]=0;
for (int i=1;i<=m;++i)
{
for (int j=0;j<=k;++j)
for (int t=0;t<=L;++t)
{
if (i<=L&&t+1<=L)
{
add(d(edges[i].u,j,t),d(edges[i].v,j,t+1),edges[t+1].data);
add(d(edges[i].v,j,t),d(edges[i].u,j,t+1),edges[t+1].data);
}
else if (i>L)
{
add(d(edges[i].u,j,t),d(edges[i].v,j,t),edges[i].data);
add(d(edges[i].v,j,t),d(edges[i].u,j,t),edges[i].data);
}
}
for (int j=0;j<=k-1;++j)
for (int t=0;t<=L-1;++t)
if (i>L)
{
add(d(edges[i].u,j,t),d(edges[i].v,j+1,t+1),edges[t+1].data);
add(d(edges[i].v,j,t),d(edges[i].u,j+1,t+1),edges[t+1].data);
}
}
dijkstra();
for (int i=0;i<=k;++i)
ans=min(ans,dis[d(n,i,L)]);
}
cout<<ans<<endl;
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983634.html

浙公网安备 33010602011771号