• NOIP2009 最优贸易


     最优贸易
    题目描述 Description
    C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市。任意两个
    城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路,一部分
    为双向通行的道路,双向通行的道路在统计条数时也计为 1 条。 
    C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价
    格不一定相同。但是,同一种商品在同一个城市的买入价和卖出价始终是相同的。 
    商人阿龙来到 C 国旅游。当他得知同一种商品在不同城市的价格可能会不同这一信息
    之后,便决定在旅游的同时,利用商品在不同城市中的差价赚回一点旅费。设 C 国 n 个城
    市的标号从 1~ n,阿龙决定从 1 号城市出发,并最终在 n 号城市结束自己的旅行。在旅游的
    过程中,任何城市可以重复经过多次,但不要求经过所有 n 个城市。阿龙通过这样的贸易方
    式赚取旅费:他会选择一个经过的城市买入他最喜欢的商品――水晶球,并在之后经过的另
    一个城市卖出这个水晶球,用赚取的差价当做旅费。由于阿龙主要是来 C 国旅游,他决定
    这个贸易只进行最多一次,当然,在赚不到差价的情况下他就无需进行贸易。 
    假设 C 国有 5 个大城市,城市的编号和道路连接情况如下图,单向箭头表示这条道路
    为单向通行,双向箭头表示这条道路为双向通行。 



    假设 1~n 号城市的水晶球价格分别为 4,3,5,6,1。 
    阿龙可以选择如下一条线路:1->2->3->5,并在 2 号城市以 3 的价格买入水晶球,在 3
    号城市以 5 的价格卖出水晶球,赚取的旅费数为 2。 
    阿龙也可以选择如下一条线路 1->4->5->4->5,并在第 1 次到达 5 号城市时以 1 的价格
    买入水晶球,在第 2 次到达 4 号城市时以 6 的价格卖出水晶球,赚取的旅费数为 5。 
    现在给出 n 个城市的水晶球价格,m 条道路的信息(每条道路所连接的两个城市的编号
    以及该条道路的通行情况)。请你告诉阿龙,他最多能赚取多少旅费。
     输入输出格式 Input/output
    输入格式:
    第一行包含 2 个正整数 n 和 m,中间用一个空格隔开,分别表示城市的数目和道路的
    数目。 
    第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 n 个城
    市的商品价格。 
    接下来 m 行,每行有 3 个正整数,x,y,z,每两个整数之间用一个空格隔开。如果 z=1,
    表示这条道路是城市 x 到城市 y 之间的单向道路;如果 z=2,表示这条道路为城市 x 和城市
    y 之间的双向道路。
    输出格式:
    输出文件 trade.out 共 1 行,包含 1 个整数,表示最多能赚取的旅费。如果没有进行贸易,
    则输出 0。
     输入输出样例 Sample input/output
     
    样例输入

    5 5
    4 3 5 6 1
    1 2 1
    1 4 1
    2 3 2
    3 5 1
    4 5 2

    样例输出

    5

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 100010;
     4 struct arc{
     5     int to,next;
     6     bool ok;
     7     arc(int x = 0,int y = -1,bool o = false){
     8         to = x;
     9         next = y;
    10         ok = o;
    11     }
    12 }e[1000010];
    13 int head[maxn],theMin[maxn],theMax[maxn],value[maxn],tot,n,m;
    14 void add(int u,int v,bool a,bool b){
    15     e[tot] = arc(v,head[u],a);
    16     head[u] = tot++;
    17     e[tot] = arc(u,head[v],b);
    18     head[v] = tot++;
    19 }
    20 queue<int>q;
    21 bool in[maxn];
    22 void spfa(){
    23     while(!q.empty()) q.pop();
    24     memset(theMin,127,sizeof(theMin));
    25     memset(in,false,sizeof(in));
    26     theMin[1] = value[1];
    27     q.push(1);
    28     while(!q.empty()){
    29         int u = q.front();
    30         q.pop();
    31         in[u] = false;
    32         for(int i = head[u]; ~i; i = e[i].next){
    33             if(e[i].ok && theMin[e[i].to] > min(theMin[u],value[e[i].to])){
    34                 theMin[e[i].to] = min(theMin[u],value[e[i].to]);
    35                 if(!in[e[i].to]){
    36                     in[e[i].to] = true;
    37                     q.push(e[i].to);
    38                 }
    39             }
    40         }
    41     }
    42 }
    43 void spfa2(){
    44     while(!q.empty()) q.pop();
    45     memset(in,false,sizeof(in));
    46     memset(theMax,0,sizeof(theMax));
    47     theMax[n] = value[n];
    48     q.push(n);
    49     while(!q.empty()){
    50         int u = q.front();
    51         q.pop();
    52         in[u] = false;
    53         for(int i = head[u]; ~i; i = e[i].next){
    54             if(e[i^1].ok && theMax[e[i].to] < max(theMax[u],value[e[i].to])){
    55                 theMax[e[i].to] = max(theMax[u],value[e[i].to]);
    56                 if(!in[e[i].to]){
    57                     in[e[i].to] = true;
    58                     q.push(e[i].to);
    59                 }
    60             }
    61         }
    62     }
    63 }
    64 int main(){
    65     int u,v,o;
    66     while(~scanf("%d %d",&n,&m)){
    67         for(int i = 1; i <= n; ++i)
    68             scanf("%d",value+i);
    69         memset(head,-1,sizeof(head));
    70         for(int i = tot = 0; i < m; ++i){
    71             scanf("%d %d %d",&u,&v,&o);
    72             add(u,v,o >= 1,o >= 2);
    73         }
    74         spfa();
    75         spfa2();
    76         int ans = 0;
    77         for(int i = 1; i <= n; ++i)
    78             ans = max(ans,theMax[i] - theMin[i]);
    79         printf("%d
    ",ans);
    80     }
    81     return 0;
    82 }
    View Code

     也可以利用tarjan进行缩点后dp。。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 100010;
     4 const int INF = 0x3f3f3f3f;
     5 int low[maxn],dfn[maxn],belong[maxn],w[maxn];
     6 int head[maxn],hd[maxn],f[maxn],g[maxn];
     7 bool sell[maxn],vis[maxn];
     8 int n,m,tot,idx,scc,ans;
     9 struct arc{
    10     int to,next;
    11     arc(int x = 0,int y = -1){
    12         to = x;
    13         next = y;
    14     }
    15 }e[1000001];
    16 stack<int>stk;
    17 void add(int *head,int u,int v){
    18     e[tot] = arc(v,head[u]);
    19     head[u] = tot++;
    20 }
    21 void tarjan(int u){
    22     dfn[u] = low[u] = ++idx;
    23     vis[u] = true;
    24     stk.push(u);
    25     for(int i = head[u]; ~i; i = e[i].next){
    26         if(!dfn[e[i].to]){
    27             tarjan(e[i].to);
    28             low[u] = min(low[u],low[e[i].to]);
    29         }else if(vis[e[i].to]) low[u] = min(low[u],dfn[e[i].to]);
    30     }
    31     if(dfn[u] == low[u]){
    32         scc++;
    33         int v;
    34         f[scc] = -INF;
    35         g[scc] = INF;
    36         do{
    37             vis[v = stk.top()] = false;
    38             stk.pop();
    39             belong[v] = scc;
    40             f[scc] = max(f[scc],w[v]);
    41             g[scc] = min(g[scc],w[v]);
    42         }while(v != u);
    43     }
    44 }
    45 void dp(int u){
    46     vis[u] = true;
    47     for(int i = hd[u]; ~i; i = e[i].next){
    48         if(!vis[e[i].to]) dp(e[i].to);
    49         if(sell[e[i].to]) f[u] = max(f[u],f[e[i].to]);
    50         sell[u] = sell[u]||sell[e[i].to];
    51     }
    52     if(sell[u]) ans = max(ans,f[u] - g[u]);
    53 }
    54 int main(){
    55     int u,v,dir;
    56     while(!stk.empty()) stk.pop();
    57     scanf("%d %d",&n,&m);
    58     memset(head,-1,sizeof(head));
    59     memset(hd,-1,sizeof(hd));
    60     for(int i = 1; i <= n; ++i)
    61         scanf("%d",w+i);
    62     for(int i = 0; i < m; ++i){
    63         scanf("%d %d %d",&u,&v,&dir);
    64         add(head,u,v);
    65         if(dir == 2) add(head,v,u);
    66     }
    67     for(int i = 1; i <= n; ++i)
    68         if(!dfn[i]) tarjan(i);
    69     for(int i = 1; i <= n; ++i){
    70         for(int j = head[i]; ~j; j = e[j].next){
    71             if(belong[i] != belong[e[j].to]) add(hd,belong[i],belong[e[j].to]);
    72         }
    73     }
    74     sell[belong[n]] = true;
    75     memset(vis,false,sizeof(vis));
    76     dp(belong[1]);
    77     printf("%d
    ",ans);
    78     return 0;
    79 }
    80 /*
    81 3 2
    82 5 3 1
    83 1 2 1
    84 2 3 1
    85 */
    View Code
  • 相关阅读:
    linux date使用
    SHELL输出带颜色字体
    vimrc配置
    你所不知道的C++
    temp
    说什么好呢3
    Extjs3 Combo实现百度搜索查询
    Extjs3笔记 fbar
    Extjs combo赋值与刷新的先后顺序
    sql中nvarchar(max)长度测试
  • 原文地址:https://www.cnblogs.com/crackpotisback/p/4375000.html
Copyright © 2020-2023  润新知