zoukankan      html  css  js  c++  java
  • USACO / Sweet Butter(SPFA || 堆+Dijkstra)

    Sweet Butter 香甜的黄油

    Greg Galperin -- 2001

    农夫John发现做出全威斯康辛州最甜的黄油的方法:糖。把糖放在一片牧场上,他知道N(1<=N<=500)只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。当然,他将付出额外的费用在奶牛上。描述

    农夫John很狡猾。他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。

    农夫John知道每只奶牛都在各自喜欢的牧场呆着(一个牧场不一定只有一头牛)。给出各头牛在的牧场和牧场间的路线,找出使所有牛到达的路程和最短的牧场(他将把糖放在那)。

    格式

    PROGRAM NAME: butter

    INPUT FORMAT:

    (file butter.in)

    第一行: 三个数:奶牛数N,牧场数P(2<=P<=800),牧场间道路数C(1<=C<=1450).

    第二行到第N+1行: 1到N头奶牛所在的牧场号.

    第N+2行到第N+C+1行: 每行有三个数:相连的牧场A、B,两牧场间距(1<=D<=255),当然,连接是双向的.

    OUTPUT FORMAT:

    (file butter.out)

    一行 输出奶牛必须行走的最小的距离和.

    SAMPLE INPUT

    3 4 5
    2
    3
    4
    1 2 1
    1 3 5
    2 3 7
    2 4 3
    3 4 5
    

    样例图形

             P2  
    P1 @--1--@ C1
        \    |\
         \   | \
          5  7  3
           \ |   \
            \|    \ C3
          C2 @--5--@
             P3    P4
    

     

    SAMPLE OUTPUT

    8
    

    {说明: 放在4号牧场最优. }

     

    分析:此题的实际模型如下:给定一个有P个顶点的无向图,选择一个顶点,使得从该点到给定的N个顶点的权值之和最小。

    堆优化Dijkstra算法

    求每对顶点之间的最短路径首先想到的便是Floyd算法:但P的范围是(P<=800)则时间复杂度为O(800^3),显然会超时。此时可以考虑使用Dijkstra算法求最短路径(Dijkstra是O(N^2)的算法),但直接使用Dijkstra仍然会超时O(800*800^2)=O(800^3),此时可以用堆进行优化。

    Dijkstra算法每次都需要在Dist[]数组中寻求一个最小值,如果图很大,则在此处花费的时间会很多,而堆则可以在O(1)的时间内马上求得最小值,并且维护一个堆所需的时间都是在log级的。因此考虑把Dist[]数组的值用堆来存储。而且用STL中的priority_queue优化dijkstra也十分方便!(某神牛语录:“Dijkstra用堆优化比不用堆优化都好写”。。。)

     

    SPFA算法

     

    对于枚举的每个牧场i,用SPFA求出到每个点的最短路如下:dist[j]表示i->j的距离,初始值为maxint,其中dist[i]=0。维护一个队列,初始为q[1]=i;由队首枚举其他的牧场j更新牧场i到j的最短距离并同时拓展队列。直到队列空为止。这样就求出了点i到所有点的最短距离。

    图储存方法:有人说用邻接表,但是我认为用链式前向星(参见Malash神牛blog)(详见http://malash.me/200910/linked-forward-star/ )更方便而且省空间。可以在不增加时间复杂度的前提下把空间优化到1000k左右。

     

    SPFA邻接表代码:

    /*
    ID:138_3531
    LANG:C++
    TASK:butter
    */
    
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<fstream>
    #include<queue>
    #include<climits>
    #include<vector>
    
    using namespace std;
    
    int num[1000];
    int dist[1000];
    
    typedef struct Edge
    {
        int v;
        int map;
    }Edge;
    
    vector <Edge> edge[1000];
    
    void spfa(int s)
    {
        bool vis[1000];
        memset(dist,127,sizeof(dist));
        memset(vis,0,sizeof(vis));
    
        dist[s]=0;
    
        queue <int> Q;
        Q.push(s);
        vis[s]=1;
    
        while(!Q.empty())
        {
            int k=Q.front();
            Q.pop();
            vis[k]=0;
    
            for (int i=0;i<edge[k].size();i++)
            {
                int to=edge[k][i].v;
                int mapp=edge[k][i].map;
                if (dist[to]>dist[k]+mapp)
                    {
                        dist[to]=dist[k]+mapp;
                        if (!vis[to])
                        {
                            Q.push(to);
                            vis[to]=1;
                        }
    
                    }
            }
        }
    
    }
    
    int main(){
        ifstream fin("butter.in");
        ofstream fout("butter.out");
    
        int n,p,c;
        fin>>n>>p>>c;
    
        memset(num,0,sizeof(num));
        for (int i=1;i<=n;i++)
        {
            int t;
            fin>>t;
            num[t]++;
        }
    
        for (int i=0;i<c;i++)
        {
            int a,b;
            fin>>a>>b;
            int mapd;
            fin>>mapd;
    
            Edge temp;
            temp.v=b;
            temp.map=mapd;
            edge[a].push_back(temp);
            temp.v=a;
            edge[b].push_back(temp);
    
        }
    
        long long ans[1000];
        memset(ans,0,sizeof(ans));
        long long minans=INT_MAX;
    
        for (int i=1;i<=p;i++)
        {
            spfa(i);
            for (int j=1;j<=p;j++)
                ans[i]+=num[j]*dist[j];
    
            if (ans[i]<minans)
                minans=ans[i];
        }
        fout<<minans<<endl;
    
        return 0;
    }

     

     

    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    2020/10/29
    2020/10/24
    2020/10/28
    2020/10/31周报
    linux shell 中判断字符串为空的正确方法
    20201107 千锤百炼软工人
    20201103 千锤百炼软工人
    20201109 千锤百炼软工人
    20201111 千锤百炼软工人
    20201105 千锤百炼软工人
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/2610850.html
Copyright © 2011-2022 走看看