【刷题】【bfs】最优贸易

题目地址:P1073 [NOIP2009 提高组] 最优贸易 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意:

  n个城市,m条道路,道路可能是单向或者双向

  同时每个城市有个商品价格,遍历中只能进行一次买卖

  从1出发到n结束,求最大获利

数据范围:

输入数据保证 1号城市可以到达n号城市。

对于 10%的数据,1≤n≤6

对于 30%的数据,1≤n≤100

对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。

对于 100%的数据,1≤n≤1000001≤m≤5000001≤xy≤n1≤z≤21≤各城市水晶球价格100。

 

先简单分类:

 

无环图的情况,可以从1出发,buy[N]记录路径上最低价格

再从n出发,sell[N]记录路径上最高的价格

则如果有边(u,v),ans=max( ans , sell[v]-buy[u] )

 

有环图,考虑tarjian缩点

然后按照无环图操作

 

 

 

以下为法2: bfs + 贪心

神奇的bfs证联通,然后贪心,求每一种可能路径上的差值,最后求结果 

#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
int n,m;
const int N=100003,M=500003;
int val[N];

int tot[2],head[2][N];
int ev[2][M<<1],enx[2][M<<1];
void add(int u,int v,int k)
{ ev[k][++tot[k]]=v,enx[k][tot[k]]=head[k][u],head[k][u]=tot[k]; }

bool link[2][N];
void bfs(int k,int st)
{
    queue <int> q;
    q.push(st),link[k][st]=true;
     
    while(!q.empty() )
    {
        int nw=q.front() ;q.pop() ;
        for(int i=head[k][nw];i;i=enx[k][i])
        {
            int nx=ev[k][i];
            if(!link[k][nx] ) 
                link[k][nx]=true,q.push(nx); 
        }
    }
}

int d[N],mx[2][N];
bool cmp(int a,int b)
{ return val[a]<val[b]; }
void get_ans(int k,int st,int v)
{
    mx[k][st]=v;
    queue <int> q;
    q.push(st);
    
    while(!q.empty() )
    {
        int nw=q.front() ;q.pop() ;
        for(int i=head[k][nw];i;i=enx[k][i])
        {
            int nx=ev[k][i];
            if(!mx[k][nx] && link[k^1][nx] ) 
                mx[k][nx]=v,q.push(nx); 
        }
    }     
}


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++ ) scanf("%d",&val[i]),d[i]=i;
    while(m--)
    {
        int qa,u,v;
        scanf("%d%d%d",&u,&v,&qa );
        add(u,v,0),add(v,u,1);
        if(qa==2 ) add(v,u,0),add(u,v,1);
    }
    
    bfs(0,1),bfs(1,n);
    sort(d+1,d+n+1,cmp);
    for(int i=1;i<=n;i++)
        if(link[0][d[i]] && link[1][d[i]] && !mx[0][d[i]] )
            get_ans(0,d[i],val[d[i]]);
    for(int i=n;i>0;i--)
        if(link[0][d[i]] && link[1][d[i]] && !mx[1][d[i]] )
            get_ans(1,d[i],val[d[i]]);
    
    int ans=0;
    for(int i=1;i<=n;i++)
        if(link[0][i] && link[1][i] )
            ans=max(ans,mx[1][i]-mx[0][i] );
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-11-07 11:30  心若笺诗  阅读(124)  评论(0编辑  收藏  举报