51nod300分试题赛艇表演

赛艇表演

题目限制

3000 ms 256 M

题目描述

小明去某个地区观看赛艇比赛,这个地区共有n个城市和m条道路,每个城市都有赛艇比赛,在第i
个城市观看赛艇表演的价钱为ai, 去其他城市观看也需要支付赛艇表演的价格。任意两个城市之

间通过一条公路连接,并且道路是双向通行的, 观看赛艇比赛时经过的每一条道路都要支付一定
的过路费,观看完比赛返回家时经过的每一条道路也要支付过路费。

对于每个城市u,你需要为小明确定一个城市v,使得从u出发,前往v看赛艇表演,再从v回到u,

u可以等于v,要求花费的总金额尽量的少。请根据题目给出的数据输出总金额。

输入格式

第一行两个正整数n和m。  
接下来m行,每行三个正整数u,v,w,表示有一条双向道路连接u和v,且每经过一次的过路费
是w。 接下来一行n个数,第i个数表示在第i个城市观看赛艇表演的价钱。

输出格式

输出一行n个数,第i个数表示从第i个城市出发至少要花多少钱

数据范围

对于前30%的数据,n<=10,m<=20。  

对于前50%的数据,n<=100,m<=500。  
对于前70%的数据,n<=1500,m<=2000。  
对于前85%的数据,图的结构以某种方式随机生成。  
对于100%的数据,n<=2e5,m<=2e5,过路费和门票钱都在[1,1e12]内。

输入样例

  4 2  
  1 2 4  
  2 3 7  
  6 20 1 25  

输出样例

  6 14 1 25  
题解

30pts:n<=10,m<=20。

给不会最短路的人的部分分。

50pts:n<=100,m<=500。

往返路费其实就是把边权乘以2。

用floyd求出最短路,然后暴力枚举就可以了。

70pts:n<=1500,m<=2000。

考虑门票钱最小的那个城市,肯定是自己在自己城市看的。

我们从这个点出发跑Dijkstra,求出到其他城市的最短路,更新其他城市的答案。

然后删掉这个点,重复以上操作。

一共要跑n遍Dijkstra,但是点的数量越来越少,所以常数很小。

85pts:图的结构随机生成。

考虑DP?

设f[u]表示点u的最小花费。

转移是用f[u] + w更新f[v],其中v和u相邻。

这个转移有环怎么办啊?

你发现这其实是个spfa。

对带环DP跑spfa就可以了。

100pts。

把图建出来,把spfa换成Dijkstra就可以了。

当然这个题可以直接建模最短路模型,省略前面所有的部分分。 在原图的基础上加一个超级源S,S到i的连边是在i城市看表演的费用。

那么S到i的最短路就是i的最小费用。

相似题目:NOIp14 寻找道路

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define int long long
const int maxn = 4e5 + 10 ;
int n,m;
struct Node{int to,next,val;}edge[maxn * 2];
int head[maxn * 2],cnt;
void add(int x,int y,int v){
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    edge[cnt].val=v;
    head[x]=cnt;
}
priority_queue<pair<int,int> >q;
int d[maxn],vis[maxn];
void dijkstra()
{
    memset(d,0x3f,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[0]=0;
    q.push(make_pair(0,0));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(int i=head[x];i;i=edge[i].next){
            int y=edge[i].to,v=edge[i].val;
            if(d[y]>d[x]+v){
                d[y]=d[x]+v;
                q.push(make_pair(-d[y],y));
            }
        }
    }
}
main()
{
    freopen("exciting.in","r",stdin);
    freopen("exciting.out","w",stdout);
    cin>>n>>m;
    for(int i=1,x,y,v;i<=m;i++)
    {
        scanf("%lld%lld%lld",&x,&y,&v);
        add(x,y,v*2);add(y,x,v*2);
    }
    for(int i=1,w;i<=n;i++){
        scanf("%lld",&w);
        add(0,i,w);add(i,0,w);
    }
    dijkstra();
    for(int i=1;i<=n;i++) printf("%lld ",d[i]);
    return 0;
}

 

posted @ 2019-11-09 15:23  寒方  阅读(358)  评论(0编辑  收藏  举报