建造高铁

不知道哪儿的题。

Description

BSNY在规划一个国家的高铁建设。这个国家有n个城市,编号从0到n-1,首都建在0点。高铁建设划归首先要保证所有城市能全部连通,于是BSNY设计了m条高铁,保证了所有城市相互连通。
其次就是时间和费用问题,对BSNY来说,他要保证从首都出发到任何城市的时间总和最小(令sum=dist[1]+dist[2]+…+dist[n-1],要求最小化sum)。在保证总时间最小的前提下,BSNY还需要费用最小,即可以从m条高铁中去掉一些,在保证时间总和最小的情况下,费用最小。
那么聪明的你通过编程来告诉他,最小的时间和费用分别是多少?

Input

第一行输入n, m
接下来m行,每行输入4个整数x, y, t, c,表示x到y点有条双向的高铁,通过时间需要t,建造费用为c

Output

输出最小时间和费用

Sample Input

#1
4 5
0 3 1 1
0 1 1 1
0 2 10 10
2 1 1 1
2 3 1 2
#2
4 5
0 3 1 1
0 1 1 1
0 2 10 10
2 1 2 1
2 3 1 2

Sample Output

#1
4 3
#2
4 4

Tips

1<=n,m<=10^5
0<=x, y

Solution

  • 在最短路的前提下维护最小生成树,处理方式类似双关键字排序
  • SPFA需要加slf优化(第一遍没加TLE了50%

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
struct JOKER{
    int b,v,w,next;//v=time,w=cost
}e[200007];
int head[100007],n,m,tot,H,T,q[5000007];
ll dis[100007],cost[100007],ans1,ans2;
bool vis[100007];
void add(int x,int y,int v,int w){
    e[++tot].b=y;
    e[tot].v=v;
    e[tot].w=w;
    e[tot].next=head[x];
    head[x]=tot;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){
        int x,y,t,c;
        scanf("%d%d%d%d",&x,&y,&t,&c);
        x++; y++;
        add(x,y,t,c); add(y,x,t,c);
    }

    for (int i=1;i<=n;i++)dis[i]=cost[i]=10000000007;
    T=1; q[1]=1; dis[1]=0; cost[1]=0; vis[1]=1;
    while (H<T){
        int u=q[++H];
        for (int i=head[u];i;i=e[i].next){
            int v=e[i].b;
            if (dis[v]>dis[u]+e[i].v){
                dis[v]=dis[u]+e[i].v;
                cost[v]=e[i].w;
                if (!vis[v]){
                    vis[v]=1;
                    if (dis[v]<dis[q[H+1]])q[H--]=v;
                        else q[++T]=v;
                }
            }
            else if (dis[v]==dis[u]+e[i].v&&cost[v]>e[i].w) cost[v]=e[i].w;
        }
        vis[u]=0;
    }

    for (int i=1;i<=n;i++){ans1+=dis[i]; ans2+=cost[i];}
    printf("%lld %lld",ans1,ans2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值