BZOJ1774: [Usaco2009 Dec]Toll 过路费

n<=250个点m<=10000边无自环图,有点权边权,Q<=10000个询问i到j的最短路。这里的路径长度指路上边权和+路上点权最大值。

n这么小,询问这么多,那就跑跑floyd吧!f[i][j]记最短路,g[i][j]记最短路上最大点权,当f[i][j]+g[i][j]>f[i][k]+f[k][j]+max(g[i][k],g[k][j])时更新答案,注意不要用无效状态即可。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<math.h>
 5 #include<iostream>
 6 using namespace std;
 7  
 8 int n,m,q;
 9 #define maxn 261
10 int f[maxn][maxn],g[maxn][maxn];
11 int x,y,v;
12 const int inf=5e8;
13 int max(int a,int b) {return a>b?a:b;}
14 int min(int a,int b) {return a<b?a:b;}
15 int main()
16 {
17     scanf("%d%d%d",&n,&m,&q);
18 //  for (int i=1;i<=n;i++)
19 //      for (int j=1;j<=n;j++)
20 //          g[i][j]=inf;
21     memset(g,0,sizeof(g));
22     for (int i=1;i<=n;i++) scanf("%d",&g[i][i]);
23     for (int i=1;i<=n;i++)
24     {
25         for (int j=1;j<=n;j++)
26             f[i][j]=inf;
27         f[i][i]=0;
28     }
29     for (int i=1;i<=m;i++)
30     {
31         scanf("%d%d%d",&x,&y,&v);
32         g[x][y]=max(g[x][x],g[y][y]);
33         g[y][x]=max(g[x][x],g[y][y]);
34         f[x][y]=min(f[x][y],v);
35         f[y][x]=min(f[y][x],v);
36     }
37 //  for (int i=1;i<=n;i++){
38 //      for (int j=1;j<=n;j++)
39 //          cout<<f[i][j]<<' ';cout<<endl;}cout<<endl;
40 //  for (int i=1;i<=n;i++){
41 //      for (int j=1;j<=n;j++)
42 //          cout<<g[i][j]<<' ';cout<<endl;}cout<<endl;
43     for (int k=1;k<=n;k++)
44         for (int i=1;i<=n;i++)
45             for (int j=1;j<=n;j++)
46                 if (!g[i][j] || (g[i][k] && g[k][j] && f[i][j]+g[i][j]>f[i][k]+f[k][j]+max(g[i][k],g[k][j])))
47                 {
48                     f[i][j]=f[i][k]+f[k][j];
49                     g[i][j]=max(g[i][k],g[k][j]);
50                 }
51 //  for (int i=1;i<=n;i++){
52 //      for (int j=1;j<=n;j++)
53 //          cout<<f[i][j]<<' ';cout<<endl;}cout<<endl;
54 //  for (int i=1;i<=n;i++){
55 //      for (int j=1;j<=n;j++)
56 //          cout<<g[i][j]<<' ';cout<<endl;}cout<<endl;
57     for (int i=1;i<=q;i++)
58     {
59         scanf("%d%d",&x,&y);
60         printf("%d\n",f[x][y]+g[x][y]);
61     }
62     return 0;
63 }
View Code

错误!本题中的最短路,枚举中转点顺序的不同会产生不同的答案。观察下图,4-5的“最短路”是2+4+9+10=25,而这需要先用到路径1-3-5(以3为中转点),再以1为中转点更新答案。

不过本题的“最短路”是有赖于图的最短路的,在最短路可以随便枚举中转点的前提下,优先考虑小权点会使最优答案被及时地更新。就是说,f[i][j]记最短路,g[i][j]记答案,从小权点到大权点枚举中转点,一边更新答案。

当然最后不要忘了有重边。。。。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<math.h>
 5 //#include<iostream>
 6 using namespace std;
 7 
 8 int n,m,q;
 9 #define maxn 261
10 int f[maxn][maxn],g[maxn][maxn];
11 int x,y,v;
12 const int inf=1e9;
13 int max(int a,int b) {return a>b?a:b;}
14 int min(int a,int b) {return a<b?a:b;}
15 int a[maxn];
16 struct Point{int id,v;bool operator < (const Point &b) const {return v<b.v;}}p[maxn];
17 int main()
18 {
19     scanf("%d%d%d",&n,&m,&q);
20     for (int i=1;i<=n;i++)
21         for (int j=1;j<=n;j++)
22             f[i][j]=g[i][j]=inf;
23     for (int i=1;i<=n;i++)
24     {
25         scanf("%d",&a[i]);
26         g[i][i]=p[p[i].id=i].v=a[i];
27         f[i][i]=0;
28     }
29     sort(p+1,p+1+n);
30     for (int i=1;i<=m;i++)
31     {
32         scanf("%d%d%d",&x,&y,&v);
33         if (v<f[x][y]) f[x][y]=f[y][x]=v;
34     }
35     for (int k=1;k<=n;k++)
36         for (int i=1;i<=n;i++)
37             for (int j=1;j<=n;j++)
38             {
39                 int x=p[k].id;
40                 f[i][j]=min(f[i][j],f[i][x]+f[x][j]);
41                 g[i][j]=min(g[i][j],f[i][j]+max(p[k].v,max(a[i],a[j])));
42             }
43     for (int i=1;i<=q;i++)
44     {
45         scanf("%d%d",&x,&y);
46         printf("%d\n",g[x][y]);
47     }
48     return 0;
49 }
View Code

 

posted @ 2017-08-30 13:43  Blue233333  阅读(185)  评论(0编辑  收藏  举报