[JSOI2010]旅行

链接:https://www.luogu.com.cn/problem/P6029

题目描述:给定一个nm条边的无向图,可以交换k组边,求1n的最短路。

题解:发现值域都比较小,考虑dp

我们可以发现,存在一个段点L,使得前L条边只换不走,后面的mL条边换为前L条边,这样走一定不会使答案更差。

dpi,j,k表示到节点i,在前L条边中选了j条边,轮换了k次的最短路。
则有:

当前边在前L条边时:

dpi,j,k+edgej+1>dpv,j+1,k

当前边不在前L条边时:

dpi,j,k+edgenow>dpv,j,k

dpi,j,k+edgej+1>dpv,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;
} 
posted @   zhouhuanyi  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示
主题色彩