P1828 [USACO3.2]香甜的黄油 Sweet Butter


原题链接

P1828
题目类型: 普 及 + / 提 高 {\color{green}{普及+/提高}} +/
AC记录:Accepted

题目大意

n n n头牛在不同的牧场,牧场之间有路线和路线的长度。现在让你找出一个牧场 k k k,使得奶牛们到牧场 k k k的总长度最短。

输入格式

第一行包含三个整数 N , P , C N,P,C N,P,C,分别表示奶牛数、牧场数和牧场间道路数。
第二行到第 N + 1 N+1 N+1行,每行一个整数,其中第 i i i行的整数表示第 i − 1 i-1 i1头奶牛所在的牧场号。
N + 2 N+2 N+2行到第 N + C + 1 N+C+1 N+C+1行,每行包含三个整数 A , B , D A,B,D A,B,D,表示牧场号为 A A A B B B的两个牧场之间有一条长度为 D D D的双向道路相连。

输出格式

输出一行一个整数,表示奶牛必须行走的最小的距离和。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input

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

S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output

8

H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain
样例如图所示。
在这里插入图片描述
把奶油放到 4 4 4牧场, 4 4 4牧场的奶牛不用走, 2 2 2牧场的奶牛要走 3 3 3距离, 3 3 3牧场的奶牛要走 5 5 5距离。所以总路程为0*1+5*1+3*1=8

数据范围

对于 100 % 100\% 100%的数据, 1 ≤ N ≤ 500 , 2 ≤ P ≤ 800 , 1 ≤ A , B ≤ P , 1 ≤ C ≤ 1450 , 1 ≤ D ≤ 255 1\le N\le 500,2\le P\le 800,1\le A,B\le P,1\le C\le 1450,1\le D\le 255 1N500,2P800,1A,BP,1C1450,1D255

解题思路

第一次看到这题,第一时间就想到的是 F l o y e d Floyed Floyed算法,但是 F l o y e d Floyed Floyed算法的时间复杂度为 Θ ( n 3 ) \Theta(n^3) Θ(n3),虽然可以接受,但是最后还要用 Θ ( n ) \Theta(n) Θ(n)的时间来遍历每个牧场的奶牛个数,时间复杂度瞬间上升到 Θ ( n 4 ) \Theta(n^4) Θ(n4),绝对超时。所以这题可以用 D i j k s t r a Dijkstra Dijkstra或者 S p f a Spfa Spfa做。
这里作者用的是堆优化的 D i j k s t r a Dijkstra Dijkstra,显然,我们只需要枚举放奶油的牧场,做 n n n D i j k s t r a Dijkstra Dijkstra,再把答案统计起来,就可以得出答案。时间复杂度 Θ ( n ( n + m ) log ⁡ 2 n ) \Theta(n(n+m)\log_2n) Θ(n(n+m)log2n)
如果有不会 F l o y e d Floyed Floyed D i j k s t r a Dijkstra Dijkstra的同学,可以 C l i c k   h e r e \color{red}{C}\color{orange}{l}\color{yellow}{i}\color{lightgreen}{c}\color{green}{k}\ \color{lightblue}{h}\color{blue}{e}\color{purple}{r}\color{plnk}{e} Click here


最后,祝大家早日
AC

上代码

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

vector<pair<int,int> >  road[810];
int                     cow[810];
int                     n,m,k;

int work(int f)
{
    priority_queue<pair<int,int> > pq;
    bool vis[810];
    int dist[810];
    memset(dist,0x7f,sizeof(dist));
    memset(vis,false,sizeof(vis));
    dist[f]=0;
    vis[f]=true;
    pq.push(make_pair(0,f));
    while(pq.size())
    {
        pair<int,int> now=pq.top();
        pq.pop();
        int step=-now.first,id=now.second;
        if(dist[id]!=step)
            continue;
        for(int i=0; i<road[id].size(); i++)
        {
            int temp=road[id][i].first;
            int val=road[id][i].second;
            if(dist[temp]>dist[id]+val)
            {
                dist[temp]=dist[id]+val;
                pq.push(make_pair(-dist[temp],temp));
            }
        }
    }
    int sum=0;
    for(int i=1; i<=n; i++)
        sum+=cow[i]*dist[i];
    return sum;
}

int main()
{
    cin>>k>>n>>m;
    for(int i=1; i<=k; i++)
    {
        int x;
        cin>>x;
        cow[x]++;
    }
    for(int i=1; i<=m; i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        road[x].push_back(make_pair(y,z));
        road[y].push_back(make_pair(x,z));
    }
    int tar=0x7fffffff;
    for(int i=1; i<=n; i++)
        tar=min(tar,work(i));
    cout<<tar<<endl;
    return 0;
}

完美切题 ∼ \sim

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值