Vijos1754 最优贸易

  • 题目大意:给定一张有向图,求从起点到终点最大值与最小值的差值(这么说还不准确,下文有解释)的最大值。

  • 思路:可以tarjan+DP,不过SPFA是可以解决的。由于只能先买入再卖出,因此要先正向spfa求出到某一点时可能的最小值,再反向spfa求出到某一点时可能的最大值,同时记录点的访问情况,这样两次都被访问过的点就在起点到终点的路径上。最后扫描这些点即可。

  • 代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=100005;
int n,m,a[maxn],ma[maxn],mi[maxn];
vector<int> g[maxn],rg[maxn];
bool can[maxn],rcan[maxn];

void init()
{
     scanf("%d%d",&n,&m);
     for (int i=1;i<=n;++i)
       scanf("%d",&a[i]);
     for (int i=1;i<=m;++i)
     {
         int a,b,c;
         scanf("%d%d%d",&a,&b,&c);
         if (c==1)
         {
             g[a].push_back(b);
             rg[b].push_back(a);
         }
         else
         {
             g[a].push_back(b);
             rg[b].push_back(a);
             g[b].push_back(a);
             rg[a].push_back(b);
         }
     }
}

queue<int> q;
bool vis[maxn];

void rspfa(int s)
{
     memset(vis,0,sizeof(vis));
     memset(ma,0,sizeof(ma));
     memset(rcan,0,sizeof(rcan));
     vis[s]=1;
     rcan[s]=1;
     ma[s]=a[s];
     q.push(s);
     while (!q.empty())
     {
           int h=q.front();
           q.pop();
           vis[h]=0;
           for (int i=0;i<rg[h].size();++i)
           {
               if (ma[rg[h][i]]<max(ma[h],a[rg[h][i]]))
               {
                   ma[rg[h][i]]=max(ma[h],a[rg[h][i]]);
                   if (!rcan[rg[h][i]])
                     rcan[rg[h][i]]=1;
                   if (!vis[rg[h][i]])
                   {
                       vis[rg[h][i]]=1;
                       q.push(rg[h][i]);
                   }
               }
           }
     }
}

void spfa(int s)
{
     memset(vis,0,sizeof(vis));
     memset(mi,0x3f3f3f,sizeof(mi));
     memset(can,0,sizeof(can));
     vis[s]=1;
     mi[s]=a[s];
     can[s]=1;
     q.push(s);
     while (!q.empty())
     {
           int h=q.front();
           q.pop();
           vis[h]=0;
           for (int i=0;i<g[h].size();++i)
           {
               if (mi[g[h][i]]>min(mi[h],a[g[h][i]]))
               {
                   mi[g[h][i]]=min(mi[h],a[g[h][i]]);
                   if (!can[g[h][i]])
                     can[g[h][i]]=1;
                   if (!vis[g[h][i]])
                   {
                       vis[g[h][i]]=1;
                       q.push(g[h][i]);
                   }
               }
           }
     }
}

int main()
{
    init();
    spfa(1);
    rspfa(n);
    int ans=0;
    for (int i=1;i<=n;++i)
    if (can[i] && rcan[i])
    if (ma[i]!=0 && mi[i]!=0x3f3f3f && ma[i]>=mi[i])
      ans=max(ans,ma[i]-mi[i]);
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值