#10076. 「一本通 3.2 练习 2」Roadblocks

传送门

题意很明确:找到第二短路

考虑 D i j k s t r a 和 S p f a Dijkstra和Spfa DijkstraSpfa算法,维护两个标记 d i s 1 [ u ] dis1[u] dis1[u] d i s 2 [ u ] dis2[u] dis2[u] d i s 1 [ u ] dis1[u] dis1[u]表示最短路
d i s 2 [ u ] dis2[u] dis2[u]表示第二短路

D i j k s t r a 算 法 Dijkstra算法 Dijkstra

#include
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e3+10;
int s,m,cnt=0;
int head[maxn],dis1[maxn],dis2[maxn],vis[maxm][maxm];

template <class t> inline void read(t &x) {
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

struct {
	int v,w,nex;
}e[maxn<<1];

struct node{
	int u,dis;
	node(int _u = 0,int _dis = 0):u(_u),dis(_dis){}
	friend bool operator < (const node &A,const node &B) {
		return A.dis>B.dis;
	}
};

void add(int u,int v,int w) {
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}

void readdata() {
	memset(head,-1,sizeof(head));
	read(s),read(m);
	rep(i,1,m) {
		int x,y,z;
		read(x),read(y),read(z);
		add(x,y,z);add(y,x,z);
	}
}

void dijkstra() {
	priority_queue<node> q;
	dis1[1]=0;
	q.push(node(1,0));
	while(q.size()) {
		node A=q.top();
		int u=A.u,dis=A.dis;
		q.pop();
		if(dis>dis2[u]) continue;//如果大于第二短路,直接跳过,不用考虑
		if(vis[u][dis]) continue;
		vis[u][dis]=true;
		for(int i=head[u];~i;i=e[i].nex) {
			int v=e[i].v,w=e[i].w;
			int d=dis+w;//d可以相当于dis2[u]+w
			if(d<dis1[v]){//如果第二短路比最短路还优,交换第一二短路
				swap(dis1[v],d);
				if(!vis[v][dis1[v]]);
				q.push(node(v,dis1[v]));
			}
			if(d>dis1[v] && d<dis2[v]){//如果小于最短路,下面套Dijkstra的标准模板
				dis2[v]=d;
				if(!vis[v][dis2[v]]);
				q.push(node(v,dis2[v]));
			}
		}
	}
}

void work() {
	memset(vis,false,sizeof(vis));
	memset(dis1,0x3f,sizeof(dis1));
	memset(dis2,0x3f,sizeof(dis2));
	dijkstra();
	printf("%d\n",dis2[s]);
}

int main() {
	freopen("a.txt","r",stdin);
	readdata();
	work();
	return 0;
}

S p f a 版 本 Spfa版本 Spfa

#include
#include
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e3+10;
int s,m,cnt=0;
int vis[maxn],head[maxn],dis[maxn][2];

template <class t> inline void read(t &x) {
	x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

struct node{
	int v,w,nex;
}e[maxn<<1];

void add(int u,int v,int w) {
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nex=head[u];
	head[u]=cnt;
}

void readdata() {
	memset(dis,0x3f,sizeof(dis));
	read(s);read(m);
	rep(i,1,m) {
		int x,y,z;
		read(x),read(y),read(z);
		add(x,y,z);add(y,x,z);
	}
}

void spfa() {
	queue<int> q;
	dis[1][0]=0;
	q.push(1);
	while(q.size()) {
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=e[i].nex) {
			int v=e[i].v,w=e[i].w;
			if(dis[v][0]>dis[u][0]+w) {//如果能够进行松弛制作
				dis[v][1]=dis[v][0];//第二短路继承dis[v][0]
				dis[v][0]=dis[u][0]+w;//更新最短路
				q.push(v);
			}
			else if(dis[v][1]>dis[u][0]+w && dis[u][0]+w!=dis[v][0]) {
			//如果最短路无法进行松弛操作且第二短路严格小于dis[u][0]+w,则可以松弛第二短路
				dis[v][1]=dis[u][0]+w;
				q.push(v);
			}
			else if(dis[v][1]>dis[u][1]+w) {
			//最后一种情况是第二短路能够自己进行松弛操作
				dis[v][1]=dis[u][1]+w;
				q.push(v);
			}
		}
	}
}

void work() {
	memset(vis,false,sizeof(vis));
	spfa();
	printf("%d\n",dis[s][1]);
}

int main() {
	//freopen("a.txt","r",stdin);
	readdata();
	work();
	return 0;
}

你可能感兴趣的:(图论,最短路)