【洛谷P1491】集合位置

题目大意:求给定的一张无向带权图的次短路。

题解:先跑一遍 spfa 求出从起点到终点的最短路,记录路径。接着枚举删边,并重新跑 spfa,统计最小值即可。
至于为什么 dp 做法不行,暂时还不清楚。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxe=2e4+10;
const int maxv=210;
const double inf=0x3f3f3f3f;

struct node{
	int nxt,to;
	double w;
}e[maxe<<1];
int tot=1,head[maxv];
inline void add_edge(int from,int to,double w){
	e[++tot]=node{head[from],to,w},head[from]=tot;
}
int n,m,pre[maxv];
double x[maxv],y[maxv],d[maxv],ans=inf;
bool in[maxv];

inline double calc(int a,int b){
	return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}

void read_and_parse(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);
	for(int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b);
		double c=calc(a,b);
		add_edge(a,b,c),add_edge(b,a,c);
	}
}

queue<int> q;

void spfa(int a,int b){
	memset(in,0,sizeof(in));
	fill(d+1,d+n+1,inf);
	q.push(1),in[1]=1,d[1]=0;
	while(q.size()){
		int u=q.front();q.pop(),in[u]=0;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;double w=e[i].w;
			if((u==a&&v==b)||(v==a&&u==b))continue;
			if(d[v]>d[u]+w){
				d[v]=d[u]+w;
				if(a==-1&&b==-1)pre[v]=u;
				if(!in[v])q.push(v),in[v]=1;
			}
		}
	}
}

void solve(){
	spfa(-1,-1);
	for(int i=n;pre[i];i=pre[i]){
		spfa(i,pre[i]);
		ans=min(ans,d[n]);
	}
	if(ans==inf)puts("-1");
	else printf("%.2lf\n",ans);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}
posted @ 2018-12-07 21:18  shellpicker  阅读(197)  评论(0编辑  收藏  举报