AcWing 3305.作物杂交(bellman-ford和spfa)

作物杂交(bellman-ford和spfa)
二者的思路是一样的,spfa是bellman-ford的优化

bellman-ford

//bellman_ford
//直接写会TLE,如何优化?——当我们发现在某一层迭代中没有一个d更新的话,就可以break了,因为只有当某个点的前驱节点更新了,该节点才会更新
#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define M 100010
struct Edge
{
    int a,b,c;//由a,b点可以生成c点
};
Edge p[M];
int n,m,k,t,w[N];//w:成熟时间
bool hav[N];//用于标记已经存在的种子
int d[N];//该号种子出现的时间(它等于它的两个前驱种子出现的时间的较大值+它的两个前驱种子成熟时间的较大值)
void bellman_ford()
{
    for(int l=1;l<=n-1;l++)//  n号点最多经过n-1次迭代
    {
        bool st=true;
        for(int i=0;i<k;i++)//遍历所有边
        {
            int a=p[i].a,b=p[i].b,c=p[i].c;
            if(hav[a]&&hav[b])
            {
                if(d[c]>max(d[a],d[b])+max(w[a],w[b]))
                {
                    d[c]=max(d[a],d[b])+max(w[a],w[b]);//(它等于它的两个前驱种子出现的时间的较大值+它的两个前驱种子成熟时间的较大值)
                    hav[c]=true;//c种子已出现,标记一下
                    st=false;                    
                }
            }
        }
        if(st)  break;//优化
    }
}
int main()
{
    cin>>n>>m>>k>>t;
    memset(d,0x3f,sizeof d);
    for(int i=1;i<=n;i++)   cin>>w[i];
    for(int i=1;i<=m;i++)//输入存在的种子
    {
        int x;
        cin>>x;
        hav[x]=true;
        d[x]=0;
    }
    for(int i=0;i<k;i++)
        cin>>p[i].a>>p[i].b>>p[i].c;
    bellman_ford();
    cout<<d[t]<<endl;
}

作者:less
链接:https://www.acwing.com/solution/content/248530/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

spfa

//spfa
//这次邻接表存的不是每个点所能到达的点和这条边的长度了,而是与某个点关联的点(例如a和b杂交得出c,则a的表里存的是b和c)
#include<bits/stdc++.h>
using namespace std;
#define N 2010
#define M 200010
int e[M],ne[M],h[N],w[N];
int n,m,k,t,idx,d[N],tar[M];//tar:某个种子a和别的种子b杂交得出的种子c,要存两遍(a,b),所以大小要开两倍
bool hav[N];
void add(int l,int r,int c)//l和r杂交得到c点
{
    e[idx]=r,ne[idx]=h[l],tar[idx]=c,h[l]=idx++;
}
queue<int> q;
bool st[N];
void spfa()
{
    while(q.size())
    {
        auto a=q.front();
        q.pop();
        st[a]=false;
        for(int i=h[a];i!=-1;i=ne[i])//取出与a(母亲点)有关联的点
        {
            int b=e[i];//另一个父亲点
            int c=tar[i];//孩子点
            if(hav[a]&&hav[b])//如果c的前驱种子a和b都存在,就有机会更新c的出现时间
            {
                if(d[c]>max(d[a],d[b])+max(w[a],w[b]))
                {
                   d[c]=max(d[a],d[b])+max(w[a],w[b]);
                   if(!st[c])   q.push(c),st[c]=true;
                } 
                hav[c]=true;
            }
        }
    }
}
int main()
{
    memset(h,-1,sizeof h);
    memset(d,0x3f,sizeof d);
    cin>>n>>m>>k>>t;
    for(int i=1;i<=n;i++)   cin>>w[i];
    for(int i=1;i<=m;i++)
    {
        int x;
        cin>>x;
        hav[x]=true;
        d[x]=0;
        q.push(x);
        st[x]=true;
    }
    for(int i=1;i<=k;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    spfa();
    cout<<d[t];
}

作者:less
链接:https://www.acwing.com/solution/content/248530/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

(思路来自”骄骄是骄傲的骄骄”的题解 )

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值