HDU1595&&HDU3986:最短路

HDU1595

HDU3986

题意:每删除一条边,可能会有一条从1到n的最短路,求最长的最短路。

题解:hdu1596有重边,hdu3986无重边。
枚举每一条边,太暴力了,肯定TLE。
那枚举哪些边好呢?显然是在没有cut边之前的最短路上的边。
why?因为非最短路的边,删去了对最短路没有影响。
第一次Dijkstra记录最短路上所有的边,然后每次去掉一条边,Dijkstra一波

 

HDU1596代码:领接表。朴素的dijkstra有重边,无法记录。

#include <bits/stdc++.h>
using namespace std;
int const inf = 0x7f7f7f7f;
int const N = 1000 + 10;
int const M = 100000 + 10;
int first[N],ne[M],to[M],w[M],from[M],tot;
int dis[N],vis[N],n,m,last[N];
void add(int u,int v,int d){
	ne[++tot] = first[u];
	from[tot] = u;
	to[tot] = v;
	w[tot] = d;
	first[u] = tot;
}
struct Node
{
	int u,len;	
	Node(int a,int b):u(a),len(b){};
	bool operator < (const Node &x) const{
		return len > x.len;
	}
};
priority_queue<Node>q;
void Dijkstra(int t,bool flag){
	for(int i=1;i<=n;i++)	dis[i] = inf;
	dis[1] = 0;
	q.push(Node(1,0));
	while(!q.empty()){
		Node p = q.top();	q.pop();
		int u = p.u;
		if(dis[u] < p.len)	continue;
		for(int i=first[u];i;i=ne[i]){
			if(i == t)	continue;
			int v = to[i],	dist = w[i];
			if(dis[v] > dis[u] + dist){
				if(flag)	last[v] =i;
				dis[v] = dis[u] + dist;
				q.push(Node(v,dis[v]));
			}
		}
	}
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		tot = 0;
		memset(first,0,sizeof(first));
		for(int i=1;i<=m;i++){
			int u,v,d;
			scanf("%d%d%d",&u,&v,&d);
			add(u,v,d);		add(v,u,d);   //有重变
		}
		Dijkstra(0,1);
		if(dis[n] == inf){
			printf("%d\n",-1);
			continue;
		}
		int ans = 0,edge;
		for(int i=n;i;i=from[edge]){
			edge = last[i];
			Dijkstra(edge,0);
			ans = max(ans,dis[n]);
		}
		if(ans == inf)	printf("%d\n",-1);
		else		printf("%d\n",ans);
	}

}

HDU3986代码:上面的代码依然可行。另外来一个朴素Dijkstra

#include <bits/stdc++.h>
using namespace std;
int const inf = 0x7f7f7f7f;
int const N = 1000 + 10;
int n,m,last[N],mp[N][N],vis[N],dis[N];
void Dijkstra(int flag){
	for(int i=1;i<=n;i++)	dis[i] = inf,vis[i] = false;
	dis[1] = 0; 
	for(int i=1;i<n;i++){
		int MIN = inf,u;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&dis[j]<MIN)
				MIN = dis[j],u = j;
		if(MIN == inf)	return; 
		vis[u] = true;
		for(int j=1;j<=n;j++){
			if(!vis[j] && mp[u][j] != inf && dis[u]+mp[u][j]<dis[j]){
				dis[j] = dis[u] + mp[u][j];
				if(flag)	last[j] = u;
			}
		}
	}
}
int main(){
	while(~scanf("%d%d",&n,&m)){
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				if(i == j)	mp[i][j] = 0;
				else 		mp[i][j] = inf;
			}
		for(int i=1;i<=m;i++){
			int u,v,d;
			scanf("%d%d%d",&u,&v,&d);
			if(mp[u][v] > d)
				mp[u][v] = mp[v][u] = d;
		}
		Dijkstra(1);
		int ans = -inf;
		for(int i=n;i!=1;i=last[i]){
			int p1 = i,	p2 = last[i];
			int tmp = mp[p1][p2];
			mp[p1][p2] = mp[p2][p1] = inf;
			Dijkstra(0);
			ans = max(ans,dis[n]);
			mp[p1][p2] = mp[p2][p1] = tmp;
		}
		printf("%d\n",ans);
	}
}

本来想用非邻接表的FIFO优化的版本,但是一直TLE,等我写出来再贴。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值