POJ4046 Sightseeing
Description
CC and MM arrive at a beautiful city for sightseeing. They have found a map of
the city on the internet to help them find some places to have meals. They like buffet
restaurants (self-service restaurants) and there are n such restaurants and m roads. All
restaurants are numbered from 1 to n. Each road connects two different restaurants.
They know the price of every restaurant. They go by taxi and they know the taxi fee
of each road.
Now they have Q plans. In each plan, they want to start from a given restaurant,
pass none or some restaurants and stop at another given restaurant. They will have a
meal at one of those restaurants. CC does not want to lose face, so he will definitely
choose the most expensive one among the restaurants which they will pass (including
the starting one and the stopping one). But CC also wants to save money, so he want
you to help him figure out the minimum cost path for each plan.
Input
There are multiple test cases in the input.
For each test case, the first line contains two integers, n, m(1<=n<=1000,
1<=m<=20000),meaning that there are n restaurants and m roads.
The second line contains n integers indicating the price of n restaurant. All
integers are smaller than 2× 9.
10
The next m lines, each contains three integers: x, y and z(1<=x, y <=n,
1<=z<=2× 9), meaning that there is a road between x and y, and the taxi fee of this
10
road is z.
Then a single line containing an integer Q follows, meaning that there are Q plans
(1<=Q<=20000).
The next Q lines, each contains two integers: s and t (1<=s, t <= n) indicating the
starting restaurant and stopping restaurant of each plan.
The input ends with n = 0 and m = 0.
Output
For each plan, print the minimum cost in a line. If there is no path from the
starting restaurant to the stopping restaurant, just print -1 instead.
Print a blank line after each test case.
Sample Input
6 7
1 2 3 4 5 6
1 2 1
2 3 2
3 4 3
4 5 4
1 5 5
2 5 2
1 4 3
5
1 4
2 3
1 5
3 5
1 6
2 1
10 20
1 2 5
1
12
00
Sample Output
7
5
8
9
-1
25
***********************************************************************************
题目大意:给定一个无向图,边上有权值,顶点也有权值。有q次询问,每次询问两个顶点,求这两个顶点之间(的路加上这条路上的最大的顶点权值)的最小值。
解题思路:这题是金华省赛的C题,当时只剩一个半小时的时候我拿到这道题,出了此题大概就可以拿金牌了,当时我的想法是n次dij做多源最短路,然后每次询问的时候用枚举n次关键点来暴力处理,但是没法过。。。赛后发现别人都是用spfa做多源最短路,我表示很不爽,竟然可以这样,然而在poj愤怒提交了46次后才ac,我才意识到,就算比赛的时候我写spfa也大概是过不了的,哎,果断是没有金牌的实力就不要希冀金牌。思路和我当时想法一样,做n次spfa预处理,在每次询问的时候枚举n个点来暴力查询。当时dijTLE了,虽然dij比spfa稳定,平时的时候dij的时间复杂度貌似也比spfa低,然而,spfa的期望复杂度是O(ke),k一般在2左右,然后,就可以在这道题目大显身手了,这题时限非常紧,一般都是几千毫秒过的,时限只给了5000MS。所以,裸的spfa和暴力询问还是会超时,在省赛当时的环境,我也没法想出优化,那么,实力不够,自认。这道题的spfa我用了SFL和LLL优化,这两个优化具体能快多少,传说是50%,不过spfa本身就不稳定,优化的速度更不稳定,就不讨论了。然后,在做spfa的时候还得动些手脚,对于i的单源最短路,被i更新的点的权值都要比i小,这样以来,如果dis[i][j]有值就说明从i到j的最短路上的最大点权值就是i的点权值。然后各种加优化才能过。。。。有点无力啊。
最新更改:我擦,黑书P308例题一,亮瞎所有去过金华省赛的ACMer的眼。
//#pragma comment(linker, "/STACK:65536000") #include <map> #include <stack> #include <queue> #include <math.h> #include <vector> #include <string> #include <fstream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <deque> #include <algorithm> #define N 1005 #define M 50000 #define E #define inf 0x3f3f3f3f #define dinf 1e10 #define linf (LL)1<<60 #define LL long long #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; int n,m,eid; LL pval[N]; int head[N],nxt[M],ed[M]; LL sum; LL val[M],dis[N][N],cun[N][N]; int inq[N],num[N],id[N]; deque<int>que; map<LL,int>hash; struct Node { int a,b;LL c; LL u; Node(int t1,int t2,LL t3) { a=t1;b=t2;c=t3; u=max(pval[a],pval[b]); } Node(){} bool operator<(const Node & t)const { return u<t.u; } }node[M]; bool cmp(int a,int b) { return pval[a]<pval[b]; } void addedge(int s,int e,LL v) { ed[eid]=e; val[eid]=v; nxt[eid]=head[s]; head[s]=eid++; } int relax(int s,int e,LL v,int k) { if(dis[k][s]+v<dis[k][e]) { if(inq[e])sum=sum-dis[k][e]+dis[k][s]+v; dis[k][e]=dis[k][s]+v; return 1; } return 0; } int main() { //freopen("/home/axorb/in","r",stdin); while(scanf("%d%d",&n,&m)==2) { if(n==0&&m==0)break; eid=0;hash.clear(); for(int i=1;i<=n;i++) { head[i]=-1;num[i]=i; scanf("%I64d",&pval[i]); } sort(num+1,num+1+n,cmp); for(int i=1;i<=n;i++) id[num[i]]=i; for(int i=1;i<=m;i++) { int a,b;LL c; scanf("%d%d%I64d",&a,&b,&c); node[i]=Node(a,b,c); } sort(node+1,node+1+m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { dis[i][j]=linf; cun[i][j]=-2; } int ke=1; for(int u=1;u<=n;u++) { int h=num[u]; if(!hash.count(pval[h]))hash[pval[h]]=u; for(;ke<=m;ke++) { if(node[ke].u>pval[h])break; addedge(node[ke].a,node[ke].b,node[ke].c); addedge(node[ke].b,node[ke].a,node[ke].c); } dis[h][h]=0; que.clear(); que.push_back(h);sum=0; for(int i=1;i<=n;i++)inq[i]=0; while(!que.empty()) { int a=que.front(); que.pop_front(); sum-=dis[h][a]; inq[a]=0; for(int i=head[a];~i;i=nxt[i]) { int e=ed[i];LL v=val[i]; if(relax(a,e,v,h)&&!inq[e]) { inq[e]=1;sum+=dis[h][e]; if(que.empty()||dis[h][e]<=dis[h][que.front()]) que.push_front(e); else que.push_back(e); } } int si=que.size(); while(si>0&&dis[h][que.front()]*si>sum) { que.push_back(que.front()); que.pop_front(); } } } int q; scanf("%d",&q); while(q--) { int a,b; scanf("%d%d",&a,&b); if(cun[a][b]!=-2) { printf("%I64d\n",cun[a][b]); continue; } LL ans=linf; int k=hash[max(pval[a],pval[b])]; for(int i=k;i<=n;i++) { int j=num[i]; if(dis[j][a]<linf&&dis[j][b]<linf) ans=min(ans,dis[j][a]+dis[j][b]+pval[j]); } printf("%I64d\n",cun[a][b]=cun[b][a]=(ans==linf?-1:ans)); } puts(""); } return 0; }