【bzoj1774-过路费】floyd+排序
题意:n个点,m条双向边,每个点有权值c[i],每条边有权值a[i].d,一条路径的费用=每条边的权值和+各个点的权值的最大值,即sigma(a[i].d)+max(c[i])。q个询问,问x到y的最小费用。n<=250,m<=10000.
题解:
1 for(int k=1;k<=n;k++)
2 {
3 int x=p[k].id;
4 for(int i=1;i<=n;i++)
5 for(int j=1;j<=n;j++)
6 {
7 int t0=maxx(w[i],w[x]),t1=maxx(w[x],w[j]);
8 dis[i][j]=minn(dis[i][j],dis[i][x]+dis[x][j]-t0-t1+maxx(t0,t1));
9 }
10 }
点按ci排序,k循环按点从小到达循环,floyd的三重循环中,k限定了当前任意的i到j的最短路径都是由1~k所更新的,也就是i到j的路径中不经过c[x]>c[k]的点。所以我们可以知道当前更新dis[i][j]的dis[i][k]和dis[k][j]这两条路径中点权的最大值分别是什么。
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 #include<queue>
7 #include<vector>
8 #include<cmath>
9 #include<deque>
10 using namespace std;
11
12 const int N=300,INF=(int)1e9;
13 int n,m,Q;
14 int w[N],dis[N][N];
15 struct node{
16 int id,d;
17 }p[N];
18
19 int minn(int x,int y){return x<y ? x:y;}
20 int maxx(int x,int y){return x>y ? x:y;}
21 bool cmp(node x,node y){return x.d<y.d;}
22
23 void floyd()
24 {
25 for(int k=1;k<=n;k++)
26 {
27 int x=p[k].id;
28 for(int i=1;i<=n;i++)
29 for(int j=1;j<=n;j++)
30 {
31 int t0=maxx(w[i],w[x]),t1=maxx(w[x],w[j]);
32 dis[i][j]=minn(dis[i][j],dis[i][x]+dis[x][j]-t0-t1+maxx(t0,t1));
33 }
34 }
35 }
36
37 int main()
38 {
39 // freopen("a.in","r",stdin);
40 freopen("toll.in","r",stdin);
41 freopen("toll.out","w",stdout);
42 scanf("%d%d%d",&n,&m,&Q);
43 int x,y,d;
44 for(int i=1;i<=n;i++)
45 {
46 scanf("%d",&w[i]);
47 p[i].id=i;p[i].d=w[i];
48 }
49 sort(p+1,p+1+n,cmp);
50 for(int i=1;i<=n;i++)
51 for(int j=1;j<=n;j++)
52 {
53 if(i==j) dis[i][j]=w[i];
54 else dis[i][j]=INF;
55 }
56 for(int i=1;i<=m;i++)
57 {
58 scanf("%d%d%d",&x,&y,&d);
59 dis[x][y]=minn(dis[x][y],d+maxx(w[x],w[y]));
60 dis[y][x]=minn(dis[y][x],d+maxx(w[x],w[y]));
61 }
62 floyd();
63 // for(int i=1;i<=n;i++)
64 // for(int j=1;j<=n;j++)
65 // printf("dis %d %d = %d\n",i,j,dis[i][j]);
66 for(int i=1;i<=Q;i++)
67 {
68 scanf("%d%d",&x,&y);
69 printf("%d\n",dis[x][y]);
70 }
71 return 0;
72 }