hpu 1413: StarFarming(图论,有向图反向存边)

来源:互联网 发布:网络打印机ip地址 编辑:程序博客网 时间:2024/06/05 22:32

传送门
题目描述
星农(StarFarming)公司计划要给员工发路费津贴,发放的规则是这样的:1到n-1代表各个员工家的序号,n代表公司。路费津贴只发给上班的最短路与回家的最短路的总路程最长的人。该市的路建造的有些奇怪,修路只修单行道,即只允许往某一个方向通行。

现在给你城市的有向图的地图,TLG请你帮忙计算谁能得到津贴,以及他上班和回家的总路程是多少。

输入
有多组测试数据。

每组第一行输入两个整数N,M。表示点的个数,与单行道的数量(可能有重复)

接下来m行,每行输入三个整数x,y,z。表示从x到y城市有一条单行道,距离为z。

题目保证至少一人存在来回的路径。不存在的不发津贴(班都没法好好上还想要钱?!)

1≤N≤10001≤N≤1000
1≤M≤1000001≤M≤100000
1≤x,y≤N1≤x,y≤N
1≤z≤2001≤z≤200
输出
对于每组数据,输出两个整数,分别表示获得津贴的人的序号以及总路程。(如果有多个人路程相同,取序号最小的)

样例输入
4 7
1 2 2
2 3 2
1 3 4
4 1 2
4 2 2
3 4 1
4 3 5
样例输出
1 7
提示
对于样例,

1来回需要的最短路程是7:1->2->3->4->1

2来回需要的最短路程是5:2->3->4->2

3来回需要的最短路程是5:3->4->2->3

所以输出1 7

在有向图中,从1到n的最短路,就是反向存边(比如1->3,就存为3->1)后,从n到1的最短路,所以跑两次Dijkstra就可以了,(比赛时是sb)第二次是在反向存边后,从n开始算到各个点的距离,就是每个点到n的最短路

Dijkstra算法如下

//52ms#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<algorithm>using namespace std;int n,m;const int MAX_E = 100010;const int INF = 0x3f3f3f3f;const int MAX_V = 1010;int e[MAX_V][MAX_V],x[MAX_E],y[MAX_E],z[MAX_E];int dis[MAX_V],dis2[MAX_V];bool used[MAX_V];void init(){    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            if(i == j)  e[i][j] = 0;            else    e[i][j] = INF;}void Dijkstra(int a_){    fill(dis+1,dis+1+MAX_V,INF);    memset(used,false,sizeof(used));    dis[a_] = 0;    while(true){        int u = -1;        for(int i=1;i<=n;i++){            if(!used[i] &&  (u == -1 ||  dis[i] < dis[u]))                u = i;        }        if(u == -1) break;        used[u] = true;        for(int i=1;i<=n;i++){            if(dis[i] > dis[u] + e[u][i])                dis[i] = dis[u] + e[u][i];        }    }}int main(void){    while(scanf("%d %d",&n,&m) != EOF){        init();        for(int i=1;i<=m;i++)            scanf("%d %d %d",&x[i],&y[i],&z[i]);        for(int i=1;i<=m;i++){            if(e[x[i]][y[i]] > z[i])                e[x[i]][y[i]] = z[i];        }        Dijkstra(n);        for(int i=1;i<=n;i++)            dis2[i] = dis[i];        init();        for(int i=1;i<=m;i++){            if(e[y[i]][x[i]] > z[i])                e[y[i]][x[i]] = z[i];        }        Dijkstra(n);        for(int i=1;i<=n;i++){            if(dis[i] < INF && dis2[i] < INF){                dis[i] += dis2[i];            }            else{                dis[i] = 0;            }        }        int u = -1;        for(int i=1;i<=n;i++){            if(u == -1 || dis[i] > dis[u])                u = i;        }        printf("%d %d\n",u,dis[u]);    }    return 0;}

我又用了一下spaf,发现只要4ms就能跑出结果了。。哎

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<queue>#include<set>#include<vector>using namespace std;const int MAX_V = 1010;const int MAX_E = 100010;const int INF = 0x3f3f3f3f;struct Edge{    int to,cost;};int n,m;vector<Edge> G[MAX_V];int x[MAX_E],y[MAX_E],z[MAX_E];int dis[MAX_V],dis2[MAX_V];bool used[MAX_V];void spfa(int a_){    queue<int> q;    fill(dis+1,dis+1+n,INF);    memset(used,false,sizeof(used));    dis[a_] = 0; q.push(a_);    used[a_] = true;    while(!q.empty()){        int k = q.front();q.pop();        for(int i=0;i<G[k].size();i++){            Edge e = G[k][i];            if(dis[e.to] > dis[k] + e.cost){                dis[e.to] = dis[k] + e.cost;                if(!used[e.to]){                    q.push(e.to);                }            }        }        used[k] = false;    }}int main(void){    while(scanf("%d %d",&n,&m) != EOF){        for(int i=1;i<=n;i++)   G[i].clear();        for(int i=1;i<=m;i++)   scanf("%d %d %d",&x[i],&y[i],&z[i]);        for(int i=1;i<=m;i++){            G[x[i]].push_back({y[i],z[i]});        }        spfa(n);        for(int i=1;i<=n;i++){            dis2[i] = dis[i];        }        for(int i=1;i<=n;i++)   G[i].clear();        for(int i=1;i<=m;i++){            G[y[i]].push_back({x[i],z[i]});        }        spfa(n);        for(int i=1;i<=n;i++){            if(dis[i] < INF && dis2[i] < INF){                dis[i] += dis2[i];            }            else    dis[i] = 0;        }        int u = -1;        for(int i=1;i<=n;i++){            if(u == -1 || dis[i] > dis[u])                u = i;        }        printf("%d %d\n",u,dis[u]);    }    return 0;}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 股票亏20个点后怎么办 摩托车给扣了怎么办 通知拘留跑了怎么办 假烟倒卖会怎么办 卖了40万假烟怎么办 刑事拘留15天了怎么办 治安传唤人不到怎么办 治安处罚有劣迹怎么办 学生怀孕了该怎么办 有病不能拘留那怎么办 拘留所不交伙食费怎么办 治安拘留不执行怎么办 释放证明书丢了怎么办 银行提前收贷款怎么办 存货周转天数高怎么办 欠款人没有财产怎么办 起诉后对方没钱怎么办 法院起诉人不到怎么办 治安拘留跑了怎么办 看守所里生病了怎么办 二审上诉被驳回怎么办 醉酒驾车取保候审以后怎么办 小案子证据不足怎么办 撞车不严重逃逸怎么办 被执行人没有财产执行怎么办 挖到人头了怎么办 取保保证金不退怎么办 被诬陷经济诈骗怎么办 醉驾刑事拘留后怎么办 被别人举报赌博怎么办 涉黄刑事拘留怎么办取保候审 换了车牌保险怎么办 车辆转让后保险怎么办 立案后警察不管怎么办 打架后对方讹人怎么办 工商被恶意举报怎么办 店铺被工商举报怎么办 被买单侠恐吓怎么办? 团伙作案刑事拘留怎么办取保 欢乐麻将老输怎么办 回不了家怎么办身份证