zoukankan      html  css  js  c++  java
  • Invitation Cards(SPFA + 反向建边)

    传送门

    • 很经典的反向建边题目,AC代码使用SPFA做的,但是刚开始用的是朴素版的dijkstra,一直RE...

    分析

    1. n个站点每个站点都要去一个人,求来回的总花销,那么可以确定的是第一个人不需要花钱,因为要从1号站台出发,所以第一个人不用动
    2. 路是单向的路,也就是有向图,从A到B和从B到A的花费很可能是不一样的
    3. 对于除第一个人之外的其他人,先到他的目标点,然后再从目标点回来,计算最短花费
    4. 因此,先正向跑一边最短路,再反向跑一遍最短路,最后计算总和就OK了
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <string>
    using namespace std;
    typedef long long ll;
    const int N = 1000010;
    bool vis[N];
    struct Edge{
    	int v, w, next;
    }edge[N], edge1[N];
    int tot, head[N], head1[N];
    ll dist[N], sum1[N], sum2[N], p, q;
    void add(int u, int v, int w){
    	edge[tot].next = head[u];
    	edge[tot].v = v;
    	edge[tot].w = w;
    	head[u] = tot;
    	edge1[tot].next = head1[v];
    	edge1[tot].v = u;
    	edge1[tot].w = w;
    	head1[v] = tot ++;
    }
    void spfa1(){
    	queue<int> q;
    	memset(dist, 0x3f3f3f3f, sizeof dist);
    	memset(vis, 0, sizeof vis);
    	dist[1] = 0;
    	q.push(1);
    	vis[1] = 1;
    	while(q.size()){
    		int t = q.front();
    		q.pop();
    		vis[t] = false;
    		for(int i = head[t]; i != -1; i = edge[i].next){
    			int to = edge[i].v;
    			int w = edge[i].w;
    			if(dist[to] > dist[t] + w){
    				dist[to] = dist[t] + w;
    				vis[t] = true;
    				q.push(to);
    			}
    		}
    	}	
    }
    void spfa2(){
    	queue<int> q;
    	memset(dist, 0x3f3f3f3f, sizeof dist);
    	memset(vis, 0, sizeof vis);
    	dist[1] = 0;
    	q.push(1);
    	vis[1] = 1;
    	while(q.size()){
    		int t = q.front();
    		q.pop();
    		vis[t] = false;
    		for(int i = head1[t]; i != -1; i = edge1[i].next){
    			int to = edge1[i].v;
    			int w = edge1[i].w;
    			if(dist[to] > dist[t] + w){
    				dist[to] = dist[t] + w;
    				vis[t] = true;
    				q.push(to);
    			}
    		}
    	}	
    }
    int main(){
    	int t;
    	cin >> t;
    	while(t --){
    		memset(head, -1, sizeof head);
    		memset(head1, -1, sizeof head1);
    		memset(sum1, 0, sizeof sum1);
    		memset(sum2, 0, sizeof sum2);
    		scanf("%lld%lld", &p, &q);
    		while(q --){
    			ll a, b, p;
    			scanf("%lld%lld%lld", &a, &b, &p);
    			add(a, b, p);
    		}
    		spfa1();
    		for(int i = 1; i <= p; i ++)
    			sum1[i] = dist[i];
    		spfa2();
    		for(int i = 1; i <= p; i ++)
    			sum2[i] = dist[i];
    		ll res = 0;
    		for(int i = 2; i <= p; i ++)
    			res += sum1[i] + sum2[i];
    		printf("%lld
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Javascript的实例化与继承:请停止使用new关键字
    关于Unicode和URL encoding入门的一切以及注意事项
    Javascript: 从prototype漫谈到继承(2)
    你真的了解setTimeout和setInterval吗?
    javascript同步分页
    jquery ui dialog去除第一个文本框焦点问题
    指定范围内的随机数
    Mac下的mysql初始密码如何重置?
    进度条插件
    浏览器事件以及事件代理
  • 原文地址:https://www.cnblogs.com/pureayu/p/14440420.html
Copyright © 2011-2022 走看看