zoukankan      html  css  js  c++  java
  • CCF 201712-4

    参考博客:CCF 201712-4(最短路径FLoyd+SPFA)

    问题描述
      小明和小芳出去乡村玩,小明负责开车,小芳来导航。
      小芳将可能的道路分为大道和小道。大道比较好走,每走1公里小明会增加1的疲劳度。小道不好走,如果连续走小道,小明的疲劳值会快速增加,连续走s公里小明会增加s2的疲劳度。
      例如:有5个路口,1号路口到2号路口为小道,2号路口到3号路口为小道,3号路口到4号路口为大道,4号路口到5号路口为小道,相邻路口之间的距离都是2公里。如果小明从1号路口到5号路口,则总疲劳值为(2+2)2+2+22=16+2+4=22。
      现在小芳拿到了地图,请帮助她规划一个开车的路线,使得按这个路线开车小明的疲劳度最小。
    输入格式
      输入的第一行包含两个整数n, m,分别表示路口的数量和道路的数量。路口由1至n编号,小明需要开车从1号路口到n号路口。
      接下来m行描述道路,每行包含四个整数t, a, b, c,表示一条类型为t,连接a与b两个路口,长度为c公里的双向道路。其中t为0表示大道,t为1表示小道。保证1号路口和n号路口是连通的。
    输出格式
      输出一个整数,表示最优路线下小明的疲劳度。
    样例说明
      从1走小道到2,再走小道到3,疲劳度为52=25;然后从3走大道经过4到达5,疲劳度为20+30=50;最后从5走小道到6,疲劳度为1。总共为76。
    数据规模和约定
      对于30%的评测用例,1 ≤ n ≤ 8,1 ≤ m ≤ 10;
      对于另外20%的评测用例,不存在小道;
      对于另外20%的评测用例,所有的小道不相交;
      对于所有评测用例,1 ≤ n ≤ 500,1 ≤ m ≤ 105,1 ≤ a, b ≤ n,t是0或1,c ≤ 105。保证答案不超过106
    样例输入
    6 7
    1 1 2 3
    1 2 3 2
    0 1 3 30
    0 3 4 20
    0 4 5 30
    1 3 5 6
    1 5 6 1
    样例输出
    76

    思路:

    1.这是一道最短路径问题,单源出发,考虑每个结点的前驱是大路还是小路.

    2.连续的小路可以先归并存入g1数组,这样就不存在前驱是小路再走小路的情况,比如1->2,2->3都是小路,则会在考虑1结点的联通路径时先计算过1->3的连续小路。  

    3.考虑到结点个数可能到500,那么稀疏矩阵,用spfa算法更快。

    问题:

    1.这里数组如果全用int类型是80分,可能是小路的中间过程可能会int越界。全用longlong又只有40分,而给出的代码是可以100分的,我没有想明白为什么g数组不能用longlong,知道的朋友可以在下方评论。

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define inf 0x3f3f3f3f
    #define N 510
    using namespace std;
    typedef long long ll;
    
    int m,n;
    int g[N][N];//这里必须用int,用long long只有40分 
    ll g1[N][N];
    ll dis[N],dis1[N];
    bool vis[N];
    void spfa(int s){
        dis[s]=dis1[s]=0;
        queue<int> Q;
        Q.push(s);
        vis[s]=1;
        while(!Q.empty()){
            int tmp=Q.front();
            Q.pop();
            vis[tmp]=0;
            for(int i=1;i<=n;i++){
                if(dis[i]>dis[tmp]+g[tmp][i]){//大路+大路 
                    dis[i]=dis[tmp]+g[tmp][i];
                    if(!vis[i]){
                        Q.push(i);
                        vis[i]=1;
                    }
                }
                if(dis[i]>dis1[tmp]+g[tmp][i]){//小路+大路 
                    dis[i]=dis1[tmp]+g[tmp][i];
                    if(!vis[i]){
                        Q.push(i);
                        vis[i]=1;
                    }
                }
                if(g1[tmp][i]!=inf){//大路+小路 
                    if(dis1[i]>dis[tmp]+g1[tmp][i]*g1[tmp][i]){
                        dis1[i]=dis[tmp]+g1[tmp][i]*g1[tmp][i];
                        if(!vis[i]){
                            Q.push(i);
                            vis[i]=1;
                        }
                    }
                }
            }
        }
    }
    int main(){
        memset(vis,0,sizeof(vis));
        memset(dis,inf,sizeof(dis)); 
        memset(dis1,inf,sizeof(dis1)); 
        memset(g,inf,sizeof(g)); 
        memset(g1,inf,sizeof(g1)); 
        scanf("%d%d",&n,&m);
        while(m--){
            int t,a,b,c;
            scanf("%d%d%d%d",&t,&a,&b,&c);
            if(t==0&&c<g[a][b]) g[a][b]=g[b][a]=c;
            else if(t==1&&c<g1[a][b]) g1[a][b]=g1[b][a]=c;
        }
        for(int i=1;i<=n;i++){//将小路合并 
            for(int j=i+1;j<=n;j++){
                for(int k=1;k<=n;k++){
                    if(k==i||k==j) continue;
                    if(g1[i][j]>g1[i][k]+g1[k][j]) g1[i][j]=g1[j][i]=g1[i][k]+g1[k][j];
                }
            }
        }
        spfa(1);
        printf("%lld",min(dis[n],dis1[n]));
        return 0;
    }
  • 相关阅读:
    Uva 10779 collector's problem
    poj 2728 最优比率树(最小生成树问题)
    LA 3126 二分图匹配 最小路径覆盖
    poj 1149 最大流构图
    Step By Step(Java XML篇)
    Step By Step(Java 输入输出篇)
    Step By Step(Java 集合篇)
    Step By Step(Java 线程篇)
    Step By Step(Java 反射篇)
    Step By Step(Java 国际化篇)
  • 原文地址:https://www.cnblogs.com/exciting/p/8595056.html
Copyright © 2011-2022 走看看