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; }