AtCoder Beginner Contest 243 E - Edge Deletion( 删除冗余最短路)

传送门
给出一个n个点m条边的无向图,求在保证任意两点的最短路不变的情况下最多可以删除几条边。其中 n300

解决这个问题关键在于一条结论:对于一条链接uv长度w的边i,若存在除uv之外的点x满足dis[u][x]+dis[x][v]w则这条边删除之后对个点之间最短路没有影响。

因为dis[u][x]+dis[x][v]w这条边完全可以使用另外一组边代替并且更优(一段长的边明显不如很多个比较短的边)

于是用Floyd算出dis[u][v]之后枚举边就能解决了。

一些结论:
利用这种方法求出剩余的边可能组成的不是一棵树,比如边长均为三的n=3的完全图。

最短路树只是对于一个确定节点u,和一个任意节点v,树上两点的路径长度等于图中两点的最短路。所以u的最短路树可以从u为起点run一遍dij求得。

代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int N=310;
const int INF=1e18;
int dis[N][N],u[N*N],v[N*N],w[N*N];
signed main(){
	int n,m;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			dis[i][j]=INF; 
	for(int i=1;i<=n;i++)dis[i][i]=0;
	for(int i=1;i<=m;i++){
		scanf("%lld%lld%lld",&u[i],&v[i],&w[i]);
		dis[u[i]][v[i]]=dis[v[i]][u[i]]=min(dis[u[i]][v[i]],w[i]);
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				dis[j][i]=dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
	int ans=0;
	for(int i=1;i<=m;i++){
		bool flag=0;
		for(int j=1;j<=n;j++){
			if(v[i]==j||u[i]==j)continue; 
			if(w[i]>=dis[u[i]][j]+dis[j][v[i]])flag=1;
		}
		if(flag)ans++;
	}
	printf("%lld",ans);
	return 0; 
} 
posted @   Xu-daxia  阅读(72)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2019-03-25 [ZJOI2015]地震后的幻想乡
2019-03-25 浅谈KMP算法
点击右上角即可分享
微信分享提示
剑桥
05:14发布
剑桥
05:14发布
4°
多云
南风
2级
空气质量
相对湿度
77%
今天
多云
4°/16°
周日
9°/19°
周一
大雨
9°/15°