NOIP最优贸易

#include<cstdio>
#define MXN 100000+1
#define MXM 10*MXN
int getint(){
    int x=0,w=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') w=0;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=(x<<3)+(x<<1)+(c-'0');
        c=getchar();
    }
    return w?x:-x;
}
void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return;
}
int n,m,x,y,z,p,end;
int price[MXN],dis[3*MXN+2];
bool vis[3*MXN+2];
int queue[MXM],head,tail;
int u[3*MXM+2],v[3*MXM+2],w[3*MXM+2],fst[3*MXN+2],nxt[3*MXM+2],top;
void add(int x,int y,int z){
    top++;
    u[top]=x,v[top]=y,w[top]=z;
    nxt[top]=fst[u[top]];
    fst[u[top]]=top;
    return;
}
void spfa(){
    for(int i=2;i<=3*n+1;i++) dis[i]=2000000000;
    dis[1]=0;
    vis[1]=true;
    queue[tail++]=1;
    int now;
    while(head!=tail){
        now=queue[head];
        vis[now]=false;
        for(int i=fst[now];i;i=nxt[i]){
            if(dis[v[i]]>dis[now]+w[i]){
                dis[v[i]]=dis[now]+w[i];
                if(vis[v[i]]==false){
                    queue[tail]=v[i];
                    vis[v[i]]=true;
                    tail=tail+1==MXM ? 0 : tail+1;
                }
            }
        }
        head=head+1==MXM ? 0 : head+1;
    }
    return;
}
int main(){
    n=getint(),m=getint();
    for(int i=1;i<=n;i++) price[i]=getint();
    for(int i=0;i<m;i++){
        x=getint(),y=getint(),p=getint();
        if(p==1){
            add(x,y,0),add(x+n,y+n,0),add(x+2*n,y+2*n,0);
            add(x,y+n,price[x]),add(x+n,y+2*n,-price[x]);
        }
        if(p==2){
            add(x,y,0),add(y,x,0);
            add(x+n,y+n,0),add(y+n,x+n,0);
            add(x+2*n,y+2*n,0),add(y+2*n,x+2*n,0);
            add(x,y+n,price[x]),add(y,x+n,price[y]);
            add(x+n,y+2*n,-price[x]),add(y+n,x+2*n,-price[y]);
        }
    }
    end=3*n+1;
    add(n,end,0),add(3*n,end,0);
    spfa();
    write(-dis[end]);
    return 0;
}
AC代码

这是一道图论题。

题意是:有n个城市之间有m条道路,每个城市都可以买到一种商品叫水晶球,同时也可以卖出水晶球,买卖价格相同但各个城市之间价格不同,记为price。商人阿龙于是准备在旅游期间倒卖水晶球。他想好好享受旅游,所以只准备做一次交易(即买一次卖一次)。他的旅行路线是从城市1到城市n,但既不必每个城市都去,也不限制每个城市只去一次。有时候城市之间的道路是单向的,但有时是双向的,但无论怎么样都算作一条道路。

输入n,m,下一行输入各城市水晶球的价格,下m行每行输入x,y,z,表示x,y之间有一条道路,z=1时指单向,z=2时指双向。

输出阿龙一次交易可以赚得的最大差价。

虽然第一眼看这道题,感觉有点像本人之前做过的一道题,那道题题解是把spfa的dis数组改成二维的了。但是发现不能这么做,因为完全不一样ORZ……

看了别人题解发现这道题可以用分层图来做:第一层表示买之前,第二层表示卖之前,第三层表示卖之后。若x→y,则在第一层x连接一条到第二层y的边权为price[x]的边,并在第二层x连接一条到第三层y的边权为-price[x]的边。同层之间连接0权边。最后设置汇点T,使第一层的点n和第三层的点n连接到T,从第一层点1开始spfa。

由于题里说阿龙也可以不做买卖,所以第一层的n也连接T

由于这样跑最短路跑出来的dis[T]≤0,所以最后输出相反数。也可以把一、二层之间的边改为负数,二、三层之间改为正数跑最长路。

这道题很有趣,用分层图做代码短效率高,非常舒服。

posted @ 2018-01-06 22:59  Halifuda  阅读(220)  评论(0编辑  收藏  举报