牛客1080D tokitsukaze and Event (双向最短路)

题目链接:https://ac.nowcoder.com/acm/contest/1080/D

首先建两个图,一个是权值为a的图,一个是权值为b的图。

从s起点以spfa算法跑权值为ai的最短路到t点,d1[ i ]数组就表示在权值为ai的图中,s点到i点的最短路。

再从t点为起点spfa算法跑权值为bi的最短路到s点,d2[ i ]数组表示在权值为bi的图中,t点到s点的最短路。

在节点i切换模式的最小伤害就是d1[ i ] + d2[ i ],倒着遍历取min即可。

AC代码:

#include<iostream>
#include<cstdio> 
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#define maxn 100005
#define inf 0x3f3f3f3f
using namespace std;
struct node{
	vector<int> w;
	vector<int> num;
}Ga[maxn],Gb[maxn];
long long int inq[maxn],inq2[maxn],d1[maxn],d2[maxn],ans[maxn];
void addedge(long long int u,long long int v,long long int a,long long int b){
	Ga[u].num.push_back(v),Ga[u].w.push_back(a);
	Ga[v].num.push_back(u),Ga[v].w.push_back(a);  
	Gb[v].num.push_back(u),Gb[v].w.push_back(b); 
	Gb[u].num.push_back(v),Gb[u].w.push_back(b);    	
}
void init(){
	memset(d1,inf,sizeof(d1));
	memset(d2,inf,sizeof(d2));
	memset(inq,0,sizeof(inq));
	memset(inq2,0,sizeof(inq2));
	memset(ans,inf,sizeof(ans));
}//初始化 
int main(){
	int n,m,s,t;
	scanf("%d%d",&n,&m);
	for(int i = 0;i<m;i++){
	    long long int u,v,a,b;
		scanf("%lld%lld%lld%lld",&u,&v,&a,&b);
		addedge(u,v,a,b);  //建两个图                		
	}
	init();
	scanf("%d%d",&s,&t);
	queue<int> q;
	q.push(s);
	inq[s] = 1,d1[s] = 0;
	while(!q.empty()){
		int now = q.front();
		q.pop();
		inq[now] = 0;
		for(int i = 0;i<Ga[now].num.size();i++ ){
			int vex = Ga[now].num[i];
			if(d1[vex] > d1[now] + Ga[now].w[i] ){
				d1[vex] = d1[now] + Ga[now].w[i];
				if(inq[vex] == 1){
					continue;
				} 
				inq[vex] = 1;
				q.push(vex);
			} 
		}
	}//第一遍spfa 
	queue<int> q2;
	q2.push(t);
	inq2[t] = 1,d2[t] = 0;
	while(!q2.empty()){
		int now = q2.front();
		q2.pop();
		inq2[now] = 0;
		for(int i = 0;i<Gb[now].num.size();i++ ){
			int vex = Gb[now].num[i];
			if(d2[vex] > d2[now] + Gb[now].w[i]){
				d2[vex] = d2[now] + Gb[now].w[i];
				if(inq2[vex] == 1){
					continue;
				} 
				inq2[vex] = 1;
				q2.push(vex);
			}
		}
	}//第二遍spfa 
	for(int i = n;i>=0;i--){
		ans[i] = min(ans[i+1],d1[i] + d2[i]);
	}//倒着扫描 ans[i]就是在i点切换模式的最小伤害 
	for(int i = 1;i<=n;i++){
		if(i == n){
			printf("%lld",ans[i]);
			return 0;
		}
		printf("%lld
",ans[i]);
	}
}
原文地址:https://www.cnblogs.com/AaronChang/p/12129633.html