洛谷 P1828 香甜的黄油 Sweet Butter

题意

有N头牛,P个牧场,C个道路,给出牛在的牧场和牧场之间的道路,求出所有牛到同一个牧场(最优解)的最短路。

做法

因为这道题牧场很多,但边的数量较少,所以我们可以用SPFA做这道题,用一个循环队列,用链表存牧场之间的道路,然后模拟从所有牧场出发的所有情况,求最短路即可。

代码

#include<bits/stdc++.h>
using namespace std;
int head[805],to[3005],net[3005],juli[3005];
int n,p,c,pp;
int x,y,s;
int cow[505];
void lianbiao(int a,int b,int c)
{
    to[++pp]=b;//下一条边连接的点更新成 b(y) 
    juli[pp]=c;//距离更新成c(s) 
    net[pp]=head[a];//下一个点的下一个点更新成原先的head(也就是原先的下一个点) 
    head[a]=pp;//下一条边更新成 pp这条边 
}//头插法,时间复杂度较低 
int SPFA(int k)
{
    int q[805];//队列 
    int v[805]={};//记录点是否出现在队列里 
    int d[805];//距离 
    for(int i=1;i<=p;++i) 
       d[i]=1e9;//初始化 
    d[k]=0;//一开始的距离是 0 
    v[k]=1;//进入队列 
    int tou=0;
    int wei=1;   
    q[wei]=k;
    while(tou!=wei)//循环队列
    {
        tou=(tou+1)%p;
        int l=q[tou];
        for(int i=head[l];i!=0;i=net[i])
        {
            int j=to[i];
            int D=juli[i];
            if(d[j]>d[l]+D)
            {
                d[j]=d[l]+D;//更新 
                if(!v[j]) 
                {
                    wei=(wei+1)%p;
                    q[wei]=j; 
                    v[j]=1;
                }
            }
        }
        v[l]=0;//移除队列 
    }
    int sum=0;
    for(int i=1;i<=n;++i)
       sum+=d[cow[i]];
    return sum;   
}
int main() 
{
    freopen("butter.in","r",stdin);
    freopen("butter.out","w",stdout);
    scanf("%d%d%d",&n,&p,&c);
    for(int i=1;i<=n;++i)
       scanf("%d",&cow[i]);
    for(int i=1;i<=c;++i)
    {      
       scanf("%d%d%d",&x,&y,&s);
       lianbiao(x,y,s);
       lianbiao(y,x,s);//路是双向的 
    }
    int ans=1e9;//记录答案 
    for(int i=1;i<=p;++i)
        ans=min(ans,SPFA(i));//求最短路 
    printf("%d\n",ans);    
    return 0;
}

 

posted @ 2022-02-12 16:20  LikC1606  阅读(41)  评论(0编辑  收藏  举报