洛谷 P2149 [SDOI2009]Elaxia的路线

题意:一张无向图求出两个点对最短路上的最长链边权和。

题解:四次dij,源点分别为 s 1 , t 1 , s 2 , t 2 s_1,t_1,s_2,t_2 s1t1s2t2,然后可以用以下两个式子的逻辑与来判断 e e e这条边在不在两个点对的最短路同向的最长链。 ( u = e . f r o m , v = e . t o , w = e . d i s t ) (u=e.from,v=e.to,w=e.dist) (u=e.from,v=e.to,w=e.dist)
d [ 0 ] [ u ] + w + d [ 1 ] [ v ] = = d [ 0 ] [ t 1 ] d[0][u]+w+d[1][v]==d[0][t1] d[0][u]+w+d[1][v]==d[0][t1]
d [ 2 ] [ u ] + w + d [ 3 ] [ v ] = = d [ 2 ] [ t 2 ] d[2][u]+w+d[3][v]==d[2][t2] d[2][u]+w+d[3][v]==d[2][t2]
如果在最长链上,就把 e e e加入一个新图中,显然,这个新图是一个 D A G DAG DAG
然后对这个 D A G DAG DAG进行拓扑排序,在拓扑排序过程中就可以进行 d p dp dp找出最长链的长度了。
然后再重新建图,用以下两个式子的逻辑与来判断 e e e这条边在不在两个点对的最短路反向的最长链。 ( u = e . f r o m , v = e . t o , w = e . d i s t ) (u=e.from,v=e.to,w=e.dist) (u=e.from,v=e.to,w=e.dist)
d [ 0 ] [ u ] + w + d [ 1 ] [ v ] = = d [ 0 ] [ t 1 ] d[0][u]+w+d[1][v]==d[0][t1] d[0][u]+w+d[1][v]==d[0][t1]
d [ 3 ] [ u ] + w + d [ 2 ] [ v ] = = d [ 2 ] [ t 2 ] d[3][u]+w+d[2][v]==d[2][t2] d[3][u]+w+d[2][v]==d[2][t2]
如果在最长链上,就把 e e e加入一个新图中,显然,这个新图是一个 D A G DAG DAG
然后对这个 D A G DAG DAG进行拓扑排序,在拓扑排序过程中就可以进行 d p dp dp找出最长链的长度了。

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;

const int N = 1500 + 3;
const int INF = 0x3f3f3f3f;

struct Edge{
	int from,to,dist;
	Edge(int from,int to,int dist):from(from),to(to),dist(dist){}
};

struct HeapNode{
	int d,u;
	HeapNode(int d,int u):d(d),u(u){}
	bool operator < (const HeapNode& rhs) const {
		return d > rhs.d;
	}
};

struct Dijkstra {
	int n,m;
	vector<Edge> edges;
	vector<int> G[N];
	bool done[N];
	int d[4][N];
	
	void init(int n) {
		this->n = n;
		for(int i=0;i<n;i++) G[i].clear();
		edges.clear();
	}
	
	void AddEdge(int from,int to,int dist) {
		edges.push_back(Edge(from,to,dist));
		m = edges.size();
		G[from].push_back(m-1);
	}
	
	void dijkstra(int s,int id) {
		priority_queue<HeapNode> q;
		for(int i=0;i<n;i++) d[id][i] = INF;
		d[id][s] = 0;
		memset(done,0,sizeof(done));
		q.push(HeapNode(0,s));
		while(!q.empty()) {
			HeapNode x = q.top(); q.pop();
			int u = x.u;
			if(done[u]) continue;
			done[u] = true;
			for(int i=0;i<G[u].size();i++) {
				Edge& e = edges[G[u][i]];
				if(d[id][e.to] > d[id][u] + e.dist) {
					d[id][e.to] = d[id][u] + e.dist;
					q.push(HeapNode(d[id][e.to],e.to));
				}
			}
		}
	}
};

struct Toposort {
	int n,m;
	int du[N];
	int len[N];
	vector<int> G[N];
	vector<Edge> edges;
	queue<int> q;
	
	inline void init(int n) {
		this->n = n;
		for(int i=0;i<n;i++) G[i].clear();
		edges.clear();
	}
	inline void AddEdge(int u,int v,int w) {
		edges.push_back(Edge(u,v,w));
		m = edges.size();
		G[u].push_back(m-1);
	}
	inline int topo() {
		int ans = 0;
		fill(du,du+n,0); fill(len,len+n,0);
		for(int i=0;i<n;i++) for(int j=0;j<G[i].size();j++) du[edges[G[i][j]].to]++;
		int tot = 0;
		for(int i=0;i<n;i++) if(!du[i]) q.push(i);
		while(!q.empty()) {
			int x = q.front(); q.pop();
			for(int j=0;j<G[x].size();j++) {
				Edge &e = edges[G[x][j]]; int t = e.to;
				du[t]--;
				len[t] = max(len[t],len[e.from]+e.dist);
				ans = max(ans,len[t]);
				if(!du[t]) q.push(t);
			}
		}
		return ans;
	}
};

Dijkstra solver1;
Toposort solver2;

int main() {
	int n,m; scanf("%d%d",&n,&m);
	solver1.init(n); 
	int s1,t1,s2,t2; scanf("%d%d%d%d",&s1,&t1,&s2,&t2); s1--; t1--; s2--; t2--;
	while(m--) {
		int u,v,w; scanf("%d%d%d",&u,&v,&w); u--; v--;
		solver1.AddEdge(u,v,w);
		solver1.AddEdge(v,u,w);
	}
	solver1.dijkstra(s1,0);solver1.dijkstra(t1,1);
	solver1.dijkstra(s2,2);solver1.dijkstra(t2,3);
	solver2.init(n);
	for(int i=0;i<solver1.edges.size();i++) {
		Edge& e = solver1.edges[i];
		int u = e.from,v = e.to,w = e.dist;
		if(solver1.d[0][u]+w+solver1.d[1][v]==solver1.d[0][t1] && solver1.d[2][u]+w+solver1.d[3][v]==solver1.d[2][t2]) {
			solver2.AddEdge(u,v,w);
		}
	}
	int ans = solver2.topo();
	solver2.init(n);
	for(int i=0;i<solver1.edges.size();i++) {
		Edge& e = solver1.edges[i];
		int u = e.from,v = e.to,w = e.dist;
		if(solver1.d[0][u]+w+solver1.d[1][v]==solver1.d[0][t1] && solver1.d[3][u]+w+solver1.d[2][v]==solver1.d[2][t2]) {
			solver2.AddEdge(u,v,w);
		}
	}
	ans = max(ans,solver2.topo());
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值