• 最优贸易 [NOIP 2009]


    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

    第一行包含 2 个正整数 n 和 m,中间用一个空格隔开,分别表示城市的数目和道路的数目。 第二行 n 个正整数,每两个整数之间用一个空格隔开,按标号顺序分别表示这 n 个城市的商品价格。 接下来 m行, 每行有 3 个正整数, x, y, z, 每两个整数之间用一个空格隔开。 如果 z=1,表示这条道路是城市 x到城市 y之间的单向道路;如果 z=2,表示这条道路为城市 x 和城市y之间的双向道路。

    Output

    共1 行, 包含 1 个整数, 表示最多能赚取的旅费。 如果没有进行贸易,则输出 0。

    Sample Input

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

    Sample Output

    5

    Hint

    数据范围: 输入数据保证 1 号城市可以到达 n号城市。 对于 10%的数据,1≤n≤6。 对于 30%的数据,1≤n≤100。 对于 50%的数据,不存在一条旅游路线,可以从一个城市出发,再回到这个城市。 对于 100%的数据,1≤n≤100000,1≤m≤500000,1≤x,y≤n,1≤z≤2,1≤各城市水晶球价格≤100。

     
    解题思路
    网上有很多关于两次SPFA的题解,这里我给大家带来另一种解法
    1.由题意可知在一个强联通分量里可以来回走,那么我们可以想到用tarjan求出强联通分量后缩点
    2.缩完点可以后dfs求答案
    对于第二步,如果dfs维护最小值,当前最大值和最小值的差更新答案,由于路径较多会TLE,70分。
    如何实现记忆化?
    用f[]数组记录从该点到T的最大值
    一开始f全清空为0,f[T]=block_T_max,往回更新
    先用v更新u,如果所有边遍历之后f[u]=0,说明到T不联通,不更新
    否则在加上自己的最大值,一起更新
    其中vis来标记访问过的联通块,避免重复计算
     
    代码
      1 //tarjan缩点+dfs
      2 #include<stack>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<iostream>
      6 #include<algorithm>
      7 #define inf 100000000
      8 #define ll long long
      9 #define maxn 100005
     10 #define maxm 500005
     11 #define RG register int
     12 #define rep(i,a,b)    for(RG i=a;i<=b;i++)
     13 #define per(i,a,b)    for(RG i=a;i>=b;i--)
     14 using namespace std;
     15 int n,m,S,T,ans;
     16 int val[maxn],bl[maxn],bln;
     17 int head1[maxn],cnt1,head[maxn],cnt;
     18 struct Edge{
     19     int u,v,next;
     20 }edge[maxm<<1];
     21 struct E{
     22     int v,next;
     23 }e[maxm<<1];
     24 struct VAL{
     25     int mx,mn;
     26 }blk[maxn];
     27 inline int read()
     28 {
     29     int x=0,f=1;char c=getchar();
     30     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
     31     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
     32     return x*f;
     33 }
     34 
     35 namespace Tarjan{
     36 
     37 int low[maxn],dfn[maxn],clc;
     38 bool vis[maxn];
     39 stack<int> stk;
     40 
     41 inline void add(int u,int v)
     42 {
     43     edge[++cnt1].v=v;
     44     edge[cnt1].u=u;
     45     edge[cnt1].next=head1[u];
     46     head1[u]=cnt1;
     47 }
     48 
     49 void tarjan(int u)
     50 {
     51     dfn[u]=low[u]=++clc;
     52     vis[u]=1;
     53     stk.push(u);
     54     for(int i=head1[u];i;i=edge[i].next)
     55     {
     56         int v=edge[i].v;
     57         if(!dfn[v])
     58         {
     59             tarjan(v);low[u]=min(low[u],low[v]);
     60         }
     61         else if(vis[v])
     62         {
     63             low[u]=min(low[u],dfn[v]);
     64         }
     65     }
     66     if(low[u]==dfn[u])
     67     {
     68         ++bln;
     69         int tmp,mn=inf,mx=0;
     70         do{
     71             tmp=stk.top();
     72             stk.pop();
     73             mn=min(mn,val[tmp]);mx=max(mx,val[tmp]);
     74             bl[tmp]=bln;
     75             if(tmp==n)T=bln;
     76             if(tmp==1)S=bln;
     77             vis[tmp]=0;
     78         }while(tmp!=u);
     79         blk[bln].mx=mx;blk[bln].mn=mn;
     80     }
     81 }
     82 
     83 }
     84 
     85 namespace SRC{
     86 bool vis[maxn];
     87 int f[maxn];//初始化设为0,当到达T时才更新
     88 //也之有u->v有值时才能更新
     89 inline void add(int u,int v)
     90 {
     91     e[++cnt].v=v;
     92     e[cnt].next=head[u];
     93     head[u]=cnt;
     94 }    
     95 /*-----------70分TLE写法-----------
     96 void dfs(int u,int mn,int sum)
     97 {
     98     if(u==T){
     99         mn=min(mn,blk[u].mn);
    100         sum=max(blk[u].mx-mn,sum);
    101         ans=max(ans,sum);return;
    102     }
    103     mn=min(mn,blk[u].mn);
    104     sum=max(blk[u].mx-mn,sum);
    105     for(int i=head[u];i;i=e[i].next)
    106     {
    107         dfs(e[i].v,mn,sum);
    108     }
    109 }--------------------------------*/
    110 
    111 void dfs(int u)
    112 {
    113     vis[u]=1;
    114     if(u==T){f[u]=max(f[u],blk[u].mx);return;}
    115     for(int i=head[u];i;i=e[i].next)
    116     {
    117         int v=e[i].v;
    118         if(!vis[v]) dfs(v);
    119         f[u]=max(f[u],f[v]);
    120     }
    121     if(f[u])f[u]=max(f[u],blk[u].mx);//f有数值才能更新
    122     ans=max(ans,f[u]-blk[u].mn);
    123 }
    124 
    125 }
    126 
    127 int main()
    128 {
    129     int opt,u,v;
    130     n=read(),m=read();
    131     rep(i,1,n)    val[i]=read();
    132     rep(i,1,m)
    133     {
    134         u=read(),v=read(),opt=read();
    135         if(opt==2)    Tarjan::add(v,u);
    136         Tarjan::add(u,v);
    137     }
    138     Tarjan::tarjan(1);
    139     rep(i,1,cnt1)
    140     {
    141         if(bl[edge[i].u]==bl[edge[i].v])continue;
    142         SRC::add(bl[edge[i].u],bl[edge[i].v]);
    143     }
    144     SRC::dfs(S);
    145     cout<<ans;
    146     return 0;
    147 }
    View Code
  • 相关阅读:
    关于使用_bstr_t的一个坑
    ubuntu下使用sublime text进行C编程开发尝鲜
    [转]在ubuntu下安装sublime text
    [转] COM编程总结
    [转]wcout输出中文却不显示出来
    理解抽象类与接口
    软件设计原则[总结]
    [转] 在图标库中,找到合适的图标 ico
    [转]单播、多播(组播)、广播简介
    NUC970开发资源
  • 原文地址:https://www.cnblogs.com/ibilllee/p/7657539.html
Copyright © 2020-2023  润新知