【题解 P8906】 Breakdown P

Luogu P8906 Breakdown P

题意:给出一个有 n 个点的有向图,每点到另一点都有一条有向边,边有权值。现有 n2 次操作,每次会删去一些边,问每次删去后从 1 号点到 n 号点经过恰好 k 条边的最短路,若无法到达输出 1
n300,k8

输入:
3 4
10 4 4
9 5 3
2 1 6
3 1
2 3
2 1
3 2
2 2
1 3
3 3
1 1
1 2
输出:
11
18
22
22
22
-1
-1
-1
-1

这道题有人说可以暴力 SPFA 过,这里讲一下我的思路。
由于求最短路,再加上 k 很小,我们可以考虑折半。
考虑 fi,j1 经过 i 条边到 j 的最短路,di,j 则为 j 经过 i 条边到 n 的最短路,这里 1i4
那么最后答案就是 min(fk/2,i+dkk/2,i) , 1in
那如何去求 fg 数组呢?
我们可以加一个数组 vi,j,u ,表示 j 经过 i 条边 到 u 的最短路,这里 1i2
那么逆向思维,从所有边都删完开始,每次加进一条边,看会对原图产生什么影响。
设此边从 xy
首先维护好 v 数组,i=1 时赋值,i=2 时就考虑一个节点经过 xy ,或从 x 出发到 y 到一个节点的最短路,复杂度 O(n)
接下来就来看 fg 数组的维护。
i=1,i=2 时直接用 v 赋值,复杂度 O(n)
i=3i=4 时分情况讨论。
若此边为路径上的第一条边,那么就是枚举两个节点 i,j ,从 xy 再经过 1 条边到 i 再经过 1/2 条边到 j ,复杂度 O(n2),但由于只会做 n 次,不会影响总复杂度。
若是第二条边或第三条边,那么只是枚举从起点到 x 再到 y 再到目标节点,复杂度 O(n)
若是第四条边,那么只是从 1/n 出发经过 3 条边到 x 再到 y 的最短路,复杂度 O(n)
最后求解答案即可。
时间复杂度 O(n3)

Code

#include<bits/stdc++.h>
#define min(a,b) (a<b?a:b)
using namespace std;
struct datay
{
	int x,y;
}l[100005];
int n,m,a[305][305],f[5][305],d[5][305],t[100005],v[3][305][305];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
	}
	for(int i=1;i<=n;i++)f[1][i]=f[2][i]=f[3][i]=f[4][i]=1e9+5;
	for(int i=1;i<=n;i++)d[1][i]=d[2][i]=d[3][i]=d[4][i]=1e9+5;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)v[1][i][j]=v[2][i][j]=1e9+5;
	}
	for(int i=1;i<=n*n+2;i++)t[i]=1e9+5;
	for(int i=1;i<=n*n;i++)
	{
		scanf("%d%d",&l[i].x,&l[i].y);
	}
	int x,y;
	for(int u=n*n;u>=1;u--)
	{
		x=l[u].x;
		y=l[u].y;
		t[u]=t[u+1];
		v[1][x][y]=a[x][y];
		for(int i=1;i<=n;i++)
		{
			v[2][i][y]=min(v[2][i][y],v[1][i][x]+a[x][y]);
			v[2][x][i]=min(v[2][x][i],a[x][y]+v[1][y][i]);
		}//维护 v 数组 
		for(int i=1;i<=n;i++)
		{
			f[1][i]=min(v[1][1][i],f[1][i]);
			d[1][i]=min(v[1][i][n],d[1][i]);
			f[2][i]=min(v[2][1][i],f[2][i]);
			d[2][i]=min(v[2][i][n],d[2][i]);
		}//维护 i=1,2 时的 f 与 d 数组 
		if(x==1)
		{
			for(int i=1;i<=n;i++)f[3][i]=min(f[3][i],a[x][y]+v[2][y][i]);
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=n;j++)
				{
					f[4][j]=min(f[4][j],a[x][y]+v[1][y][i]+v[2][i][j]);
				}
			}
		}
		if(y==n)
		{
			for(int i=1;i<=n;i++)d[3][i]=min(d[3][i],a[x][y]+v[2][i][x]);
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=n;j++)
				{
					d[4][j]=min(d[4][j],v[2][j][i]+v[1][i][x]+a[x][y]);
				}
			}
		}//维护第1条边的情况 
		for(int i=1;i<=n;i++)
		{
			f[3][i]=min(f[3][i],v[1][1][x]+a[x][y]+v[1][y][i]);
			d[3][i]=min(d[3][i],v[1][i][x]+a[x][y]+v[1][y][n]);
			if(y==i)f[3][i]=min(f[3][i],v[2][1][x]+a[x][y]);
			if(x==i)d[3][i]=min(d[3][i],a[x][y]+v[2][y][n]);
		}//i=3的其他情况 
		for(int i=1;i<=n;i++)
		{
			f[4][i]=min(f[4][i],v[1][1][x]+a[x][y]+v[2][y][i]);
			d[4][i]=min(d[4][i],v[2][i][x]+a[x][y]+v[1][y][n]);
			f[4][i]=min(f[4][i],v[2][1][x]+a[x][y]+v[1][y][i]);
			d[4][i]=min(d[4][i],v[1][i][x]+a[x][y]+v[2][y][n]);
			if(y==i)f[4][i]=min(f[4][i],f[3][x]+a[x][y]);
			if(x==i)d[4][i]=min(d[4][i],a[x][y]+d[3][y]);
		}//i=4的其他情况 
		for(int i=1;i<=n;i++)t[u]=min(t[u],f[m/2][i]+d[m-m/2][i]);
	}
	for(int i=1;i<=n*n;i++)printf("%d\n",t[i+1]>1e9?-1:t[i+1]);








  return 0;
}
posted @   dijah  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示