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 }
错误!本题中的最短路,枚举中转点顺序的不同会产生不同的答案。观察下图,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 }