JZOJ 1622. 【Usaco2009 gold 】过路费【图论借用】

目录:


题目:

单击查看题目


分析:

看完题目,我们很容易想到使用 F l o y d 算法,在时间上n<=250,可以通过,但 F l o y d 中参加运算的只有边权,可这道题目偏偏还要个点权,我们不妨建两个数组,一个用来保存 F l o y d 的结果,另一个是在 F l o y d 的基础上加上最大的点权
对此,我们可以提前对点权进行从小到大的排序,在 F l o y d 时,最大的点权就会在i,j,k中产生
这是因为我们在之前从小到大排序了,而i,j,k中的某一个肯定是在i到j这条路径上最大的(请消化消化)


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
inline LL read()
{
    LL d=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
    return d*f;
}
struct node{
    int x,y;
}x[251];
int newid[251];
int f[251][251],ans[251][251];
bool cmd(node a,node b)
{
    return a.x<b.x;
}
int min(int a,int b)
{
    return a<b? a:b;
}
int max(int a,int b)
{
    return a>b? a:b;
}
int main()
{
    freopen("toll.in","r",stdin);
    freopen("toll.out","w",stdout);
    int n=read(),m=read(),q=read();
    for(int i=1;i<=n;i++)
      x[i].x=read(),x[i].y=i;
    sort(x+1,x+1+n,cmd);
    for(int i=1;i<=n;i++) newid[x[i].y]=i;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        f[i][j]=ans[i][j]=99999999;
    int a,b,w;
    for(int i=1;i<=m;i++)
    {
        a=newid[read()];b=newid[read()];w=read();
        f[a][b]=f[b][a]=min(w,f[a][b]);
    }
    for(int k=1;k<=n;k++)
      for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
          {
              f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
              ans[i][j]=min(ans[i][j],f[i][j]+max(x[k].x,max(x[i].x,x[j].x)));
          }
    for(int i=1;i<=q;i++)
    {
        a=read();b=read();
        printf("%d\n",ans[newid[a]][newid[b]]);
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/80961687
今日推荐