NOIP 2009 提高组 复赛 trade 最优贸易

来源:互联网 发布:钢雨篷荷载计算软件 编辑:程序博客网 时间:2024/05/22 03:38
//P1073 最优贸易
//NOIP 2009 提高组 复赛 trade 最优贸易
//http://blog.csdn.net/Qantun_Mechanics/article/details/51265515此文写得不错 ,摘抄如下:
//这个题目的解题思路比较多我就用了最蠢的跑两边spfa的做法写的。
//首先看题目以后我们知道这个题目一定是贪心,贪心的思路也很简单就是在最便宜的地方买商品在最贵的地方卖出去赚取差价,但是如果我们直接比较出最大值最小值做差是有问题的,当然不可能这个简单这个题目是当年的压轴题啊。这里写图片描述这么简单怎么玩。【虽然实际上也不难】因为那个人在不断的往前面走并在前面买东西在后面卖,所以我就把原来的边拆了建在两个图上。把所有的边正向建一张图,然后把边反过来再建一次,这样我原来的图就有两个了,于是我在正向的图上跑一边SPFA**不断更新从1到该点的最小值然后我再在反向的图上面跑第二遍SPFA然后更新最大值**并且把每个点的最大值与最小值做差来更新答案。这样就是正确的姿势啦。
//【证明】因为我们正向的跑了一边spfa更新最小值就相当于把起点到每个点的最小值求出来了,然后我第二遍spfa就做了两件事情第一个证明了连通性【因为我这个题目中有一些路是单向的,所以说可能某些点买的价格特别低或者特别高,但是我去的那儿是陷阱,你进去了就出不来了这样你的答案就是错的了,所以我把图反过来建这样你从终点可以反着跑到这个点也就代表这个点可以正着跑到终点,这就相当于证明了连通性】
//第二个事情就是不断的货比三家,计算利润和差值。
//http://hzwer.com/1144.html此文代码写得不错。
//邻接矩阵爆内存,只能邻接表,一个正向表,统计到达该点的最小值,一个反向表,统计该点到终点的最大值。
//感慨,有段时间没接触图了,确实有一定遗忘,spfa确实是重头戏,需要经常练习。2017-8-12 22:40 AC
//该题有句话,很关键:输入数据保证 1 号城市可以到达 n 号城市。
#include <stdio.h>
#include <string.h>
int head1[100000+100],head2[100000+100],cnt1=0,cnt2=0,mn[100000+100],mx[100000+100],p[100000+100],q[100000*10],inq[100000+100],n;//mn[]最小值 到达该点的最小值,mx[]最大值 该点到终点的最大值,p[]价格 q[]队列inq[]是否在队列中 n 点的个数
struct node{
    int to,next;//to下一个节点,next下一条边
}e1[500000*2+100],e2[500000*2+100];//1 注意,正向图,反向图存储在不同空间。
int min(int a,int b){
    return a>b?b:a;
}
int max(int a,int b){
    return a>b?a:b;
}
void addedge(int u,int v){
    cnt1++,e1[cnt1].next=head1[u],e1[cnt1].to=v,head1[u]=cnt1;//正向图
    cnt2++,e2[cnt2].next=head2[v],e2[cnt2].to=u,head2[v]=cnt2;//反向图
}
void spfa1(){//找最小值
    int h=0,t=0,u,v,i;
    memset(inq,0,sizeof(inq));
    q[t]=1;
    t++;
    inq[1]=1;
    mn[1]=p[1];
    while(h<t){
        u=q[h];
        inq[u]=0;
        for(i=head1[u];i;i=e1[i].next){
            v=e1[i].to;
            if(mn[u]<mn[v]||p[v]<mn[v]){
                mn[v]=min(mn[u],p[v]);
                if(!inq[v]){
                    q[t]=v;
                    t++;
                    inq[v]=1;
                }
            }
        }
        h++;
    }
}
void spfa2(){//找最大值
    int h=0,t=0,u,v,i;
    memset(inq,0,sizeof(inq));
    q[t]=n;
    t++;
    inq[n]=1;
    mx[n]=p[n];
    while(h<t){
        u=q[h];
        inq[u]=0;
        for(i=head2[u];i;i=e2[i].next){
            v=e2[i].to;
            if(mx[u]>mx[v]||p[v]>mx[v]){
                mx[v]=max(mx[u],p[v]);
                if(!inq[v]){
                    q[t]=v;
                    t++;
                    inq[v]=1;
                }
            }
        }
        h++;
    }
}
int main(){
    int m,i,x,y,z,ans=0;
    memset(head1,0,sizeof(head1));
    memset(head2,0,sizeof(head2));
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%d",&p[i]);
        mn[i]=1000;
        mx[i]=-1;
    }
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&z);
        addedge(x,y);
        if(z==2)
            addedge(y,x);
    }
    spfa1();
    spfa2();
    for(i=1;i<=n;i++)
        ans=max(ans,mx[i]-mn[i]);//找出最大差价
    printf("%d\n",ans);
    return 0;
}  


原创粉丝点击