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;
}

 

 

posted @ 2012-07-26 23:13  AbandonZHANG  阅读(585)  评论(0编辑  收藏  举报