hdu1595

该博客探讨了在图中删除最短路上的一条边以最大化剩余路径最短路长度的问题。作者指出,即使存在多条最短路径,只需考虑一条即可。删除最短路径上的边,如果最短路径没有重合边,结果不会改变;如果有重合边,删除重合边会导致图不连通。博客提供了一段AC代码来解决此问题,并警告记录所有最短路上的边会导致内存限制错误。
摘要由CSDN通过智能技术生成

题意

删除1—N最短路上的一条边,使图剩下部分1—N的最短路最长  

关于多条最短路:

这道题目的思路还是很容易想到的,我们直接找最短路,然后枚举删除最短路上的边,然后找出结果就行了。但值得一提的是,开始自己考虑了有多条最短路的问题,然后我就将所有最短路上的边都进行标记,然后就MLE了,感觉出题不严谨。其实不是,就算有多条最短路,我们只需要其中一条就行了。

多条最短路有两种情况

  1. 最短路没有重合边:这个时候我们删除任意其中一条最短路上的边,求出的最短路还是不变的。
  2. 两条最短路有重合边,这个时候我们只要删除一条重合边,就能让图不连通。
  3. 多条最短路头重合边,可以分别转化成1、2的情况

 

 只找出一条最短路就可以,AC代码

#include <bits/stdc++.h> 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define res register int 
const int maxn=1005;
int N,M;
int dis[maxn][maxn];
int pre[maxn];

int dij1()
{
	int len[maxn],vis[maxn];
	memset(vis,0,sizeof(vis));
	memset(len,inf,sizeof(len));
	len[1]=0;
	for(res i=2;i<=N;i++){
		len[i]=dis[1][i];
		if(inf!=dis[1][i]) pre[i]=1;
	}
	vis[1]=1;
	for(res i=1;i<=N-1;i++){
		int minc=inf,p=-1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]<minc){
				minc=len[j];
				p=j;
			}
		}
		if(inf==minc) break;
		vis[p]=1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]>len[p]+dis[p][j]){
				len[j]=len[p]+dis[p][j];
				pre[j]=p;
			}
		}
	}
	if(inf==len[N]) return -1;
	else return len[N];
}

int dij2()
{
	int len[maxn],vis[maxn];
	memset(vis,0,sizeof(vis));
	memset(len,inf,sizeof(len));
	len[1]=0;
	for(res i=2;i<=N;i++){
		len[i]=dis[1][i];
	}
	vis[1]=1;
	for(res i=1;i<=N-1;i++){
		int minc=inf,p=-1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]<minc){
				minc=len[j];
				p=j;
			}
		}
		if(inf==minc) break;
		vis[p]=1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]>len[p]+dis[p][j])
				len[j]=len[p]+dis[p][j];
		}
	}
	if(inf==len[N]) return -1;
	else return len[N];
}

int main()
{
	while(EOF!=scanf("%d%d",&N,&M))
	{
		//init
		for(res i=0;i<=N;i++){
			for(res j=0;j<=N;j++){
				dis[i][j]=inf;
			}
			dis[i][i]=0;
			pre[i]=-1;
		} 
		 
		int from,to,val;
		for(res i=0;i<M;i++){
			scanf("%d%d%d",&from,&to,&val);
			dis[from][to]=dis[to][from]=val; 
		}		
		int ans=dij1();
		if(-1==ans){
			printf("-1\n");
			continue;
		}
		//开始枚举每一条边
//		for(res i=1;i<=N;i++){
//			printf("%d:",i); 
//			for(res j=0;j<pre[i].size();j++){
//				printf("%d ",pre[i][j]);
//			} 
//			printf("\n");
//		}
		ans=-inf;
		int flag=0;
		int t=N;
		while(-1!=pre[t]){
			int to=t,from=pre[t];
			int temp1=dis[from][to],temp2;
			dis[from][to]=dis[to][from]=inf;
			temp2=dij2();
			if(-1==temp2){
				ans=-1;
				flag=1;
				break;
			} 
			ans=max(ans,temp2);
			dis[from][to]=dis[to][from]=temp1;
			t=pre[t];	
		}
		printf("%d\n",ans);
	}
}

记录所有最短路上的边就MLE

#include <bits/stdc++.h> 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define res register int 
const int maxn=1005;
int N,M;
int dis[maxn][maxn];
vector<int> pre[maxn];
vector<int> e[maxn];

int dij1()
{
	int len[maxn],vis[maxn];
	memset(vis,0,sizeof(vis));
	memset(len,inf,sizeof(len));
	len[1]=0;
	for(res i=2;i<=N;i++){
		len[i]=dis[1][i];
		if(inf!=dis[1][i]) pre[i].push_back(1);
	}
	vis[1]=1;
	for(res i=1;i<=N-1;i++){
		int minc=inf,p=-1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]<minc){
				minc=len[j];
				p=j;
			}
		}
		if(inf==minc) break;
		vis[p]=1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]>len[p]+dis[p][j]){
				len[j]=len[p]+dis[p][j];
				pre[j].clear();
				pre[j].push_back(p);
//				e[p].clear();
//				e[p].push_back((edge){j,dis[p][j]});
			}else if(!vis[j]&&len[j]==len[p]+dis[p][i]){
				pre[j].push_back(p); 
//				e[p].push_back((edge){j,dis[p][j]});
			}
		}
	}
	if(inf==len[N]) return -1;
	else return len[N];
}

int dij2()
{
	int len[maxn],vis[maxn];
	memset(vis,0,sizeof(vis));
	memset(len,inf,sizeof(len));
	len[1]=0;
	for(res i=2;i<=N;i++){
		len[i]=dis[1][i];
	}
	vis[1]=1;
	for(res i=1;i<=N-1;i++){
		int minc=inf,p=-1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]<minc){
				minc=len[j];
				p=j;
			}
		}
		if(inf==minc) break;
		vis[p]=1;
		for(res j=1;j<=N;j++){
			if(!vis[j]&&len[j]>len[p]+dis[p][j])
				len[j]=len[p]+dis[p][j];
		}
	}
	if(inf==len[N]) return -1;
	else return len[N];
}

void dfs(int n)
{
	if(1==n) return;
	int fa;
	for(res i=0;i<pre[n].size();i++){
		fa=pre[n][i];
		dfs(fa);
		e[fa].push_back(n);
	}
}

int main()
{
	while(EOF!=scanf("%d%d",&N,&M))
	{
		//init
		for(res i=0;i<=N;i++){
			e[i].clear();			
			for(res j=0;j<=N;j++){
				dis[i][j]=inf;
			}
			dis[i][i]=0;
		} 
		 
		int from,to,val;
		for(res i=0;i<M;i++){
			scanf("%d%d%d",&from,&to,&val);
			dis[from][to]=dis[to][from]=val; 
		}		
		int ans=dij1();
		if(-1==ans){
			printf("-1\n");
			continue;
		}
		dfs(N);
		//开始枚举每一条边
//		for(res i=1;i<=N;i++){
//			printf("%d:",i); 
//			for(res j=0;j<pre[i].size();j++){
//				printf("%d ",pre[i][j]);
//			} 
//			printf("\n");
//		}
		ans=-inf;
		int flag=0;
		for(res i=1;i<=N;i++){
			for(res j=0;j<e[i].size();j++){
				int to=e[i][j];
				int temp1=dis[i][to],temp2;
				dis[i][to]=dis[to][i]=inf;
				temp2=dij2();
				if(-1==temp2){
					ans=-1;
					flag=1;
					break;
				} 
				ans=max(ans,temp2);
				dis[i][to]=dis[to][i]=temp1;
			}
			if(flag) break;
		} 
		printf("%d\n",ans);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值