zoukankan      html  css  js  c++  java
  • 城市交通费

    城市交通费
    【问题描述】
    有 n 个城市, 编号 1~n。 其中 i 号城市的繁华度为 pi。 省内有 m 条可以双向同行的高速
    公路, 编号 1~m。 编号为 j 的高速公路连接编号为 aj 和 bj 两个城市, 经过高速公路的费用
    是 wj。 若从城市 x 出发到某城市 y, 除了需要缴纳高速公路费用, 还要缴纳“城市建设费”
    (为从 x 城市到 y 城市所经过的所有城市中繁华度的最大值, 包括 x 和 y 在内) 。
    现提出 q 个询问, 每个询问给出一组 x 和 y, 你需要回答从 x 出发到 y 城市, 所需要的
    最低交通费(高速公路费+城市建设费) 是多少。
    【输入】
    第一行三个整数 n,m,q。
    第二行 n 个整数, 表示 p1~pn。
    接下来 m 行中, 每行 3 个正整数, 第 j 行包含 Aj, Bj, Wj。
    随后 Q 行每组两个正整数 x, y 表示一组询问。
    【输出】
    共 Q 行, 为对 Q 个问题的回答: x 城市到 y 城市的最小交通费用。
    【样例输入】
    5 7 2
    2 5 3 3 4
    1 2 3
    1 3 2
    2 5 3
    5 3 1
    5 4 1
    2 4 3
    3 4 4
    1 4
    2 3
    【样例输出】
    8 9
    【数据范围及约定】
    n≤250, m≤20000, Q≤10000, Pi≤10000, Wj≤2000, 保证任意两个城市可以互相到达。
    【样例说明】
    图中, 代表城市的格子中第一个数字是城市编号, 第二个红色数字是该城市的繁华度。
    (1) 从城市 1 到城市 4 的最小交通费用路线是: 1 3 5 4; 公路费是 2+1+1=4; 城市建设费是
    max{2,3,4,3}=4; 总交通费用 4+4=8。
    (2) 从城市 2 到城市 3 的最小交通费用路线是: 2 5 3; 公路费是 3+1=4; 城市建设费是
    max{5,4,3}=5; 总交通费用 4+5=9。

    由于这个题是多组询问,显然要用floyd做,但关键是如何处理繁华度这个东西,因为最短路径和最小繁华度的路径很有可能不是一条路

    我们可以考虑对繁华度进行排序,并记录下来排序之后每个点对应的编号,然后再跑一遍floyd

    但是这样的正确性是如何保证的?这就要说到floyd的本质思想了

    因为floyd的本质其实是DP,我们记Fk,i,j表示当前情况下从i到j在经过中间点的标号不超过k时的最短路(1~k这些点可以经过也可以不经过),那么DP的状态转移方程就是Fk,i,j=min(Fk-1,i,j,Fk-1,i,k+Fk-1,k,j)也就是说在经过k和不经过k之中取最大值

    那么对于这道题来说,Fk,i,j 就表示在经过繁华度前k小的城市的前提下,从i~j的最短路径,那么因为最终的答案要考虑最大繁华度,又由于繁华度是按照从小到大的顺序排序的,所以最大繁华度只能在i,j,k 之间选取。

    for(int k=1;k<=n;k++)//floyd枚举中间点 
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    a[i][j]=min(a[i][j],a[i][t[k]]+a[t[k]][j]);//松弛两个点之间的最短路 
                    f[i][j]=min(f[i][j],a[i][j]+max(p[i],max(p[j],p[t[k]])));//最小花费 
           }

    那么有的小伙伴(@YY)就要问了,如果我们刚开始没有用k来更新最短路,那么下面岂不是还会用k来更新,这不就矛盾了吗?

    其实并不矛盾

    当点k不经过的时候,a[i][j]是没有被更新的,而f[i][j]在取min之前仍然是在经过繁华度前k-1小的城市的前提下,从i~j的最短路径。

    以下分两种情况

    1.p[k]<max(p[i],p[j])

      此时显然p[k]不会对答案产生影响

    2.p[k]>max(p[i],p[j])

      此时因为这些城市已经按照繁华度排序了,所以有p[k]>p[k-1],也就是说由于取min,p[k]不会对答案产生影响

    所以这种担心是不成立的

     

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    using namespace std;
    int n,m,q,p[300],aj,bj,wj,x,y,f[300][300],a[300][300],top,t[300];
    int cmp(int x,int y)
    {
        return p[x]<p[y];
    }
    int main()
    {
        //freopen("road.in","r",stdin);
        //freopen("road.out","w",stdout);
        memset(a,63,sizeof(a));
        top=0;
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)
            scanf("%d",&p[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&aj,&bj,&wj);
            a[aj][bj]=min(a[aj][bj],wj);
            a[bj][aj]=min(a[bj][aj],wj);
        }
        //邻接矩阵存图,由于毒瘤数据有重复的边,所以取最小值
        for(int i=1;i<=n;i++)
        {
            a[i][i]=0;//自己到自己的距离为0 
            t[i]=i;//节点的标号 
        }
        sort(t+1,t+1+n,cmp);//将城市按照繁华度排序,相当于是开了一个结构体
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                f[i][j]=a[i][j]+max(p[i],p[j]);
        //初始化 
        for(int k=1;k<=n;k++)//floyd枚举中间点 
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    a[i][j]=min(a[i][j],a[i][t[k]]+a[t[k]][j]);//松弛两个点之间的最短路 
                    f[i][j]=min(f[i][j],a[i][j]+max(p[i],max(p[j],p[t[k]])));//最小花费 
                }
        for(int i=1;i<=q;i++)
        {
            scanf("%d%d",&x,&y);
            printf("%d
    ",f[x][y]);
        }
        //fclose(stdin);
        //fclose(stdout);
        return 0;
         
    }
  • 相关阅读:
    UI:UITableView表视图
    UI:页面传值、单例模式传值、属性传值、NSUserDefaults 数据持久化
    UI:UINavigationController、界面通信
    UI:UIScrollView、UIPageControl
    UI:tomcat(说话小程序)、相框动画、UISgmentcontrol、UISwitch
    UI:触摸事件 与 事件的回应
    UI:转自互联网资料
    UI:MVC设计模式
    OC:copy 与 retain 的区别
    UI:数据持久化
  • 原文地址:https://www.cnblogs.com/lcezych/p/11010002.html
Copyright © 2011-2022 走看看