[NOIP2009提高组]最优贸易 tarjan题解

今天刚刚学会了用tarjan写缩点(以前用两遍dfs写的),此题调了我很久,需要考虑的情况有些多,但是做出来还是挺开心的。

首先通过tarjan缩点,之后要干的事情就是计算答案。

答案有两种情况,一是在一个联通块中买进卖出,二是在一个联通块中买入,但在另外一个联通块中卖出。但是需要注意的是,以上两种情况中的联通块需要满足起点可以到达它,它也可以到达终点,并且不在一个联通块中时,买进必在卖出前。

代码中的dp(x)记录的是从起点到现在买进价最低的,每次只要用当前最大价钱减去这个值,再去和ans做比较,就是第二种情况,而第一种情况还是非常好写的。

下面是我的代码,请无视那么多的注释(调试信息)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 using namespace std;
  5 const int maxn=100005;
  6 const int maxm=1000005;
  7 int dfn[maxn],low[maxn],st[maxn];
  8 bool instack[maxn];
  9 int now;
 10 int n,m;
 11 int cnt;
 12 int to[maxm],next[maxm],head[maxn];
 13 int dp[maxn];
 14 int col[maxn];
 15 int small[maxn],big[maxn];
 16 int val[maxn];
 17 int p[maxn];
 18 int u[maxm],h[maxm];
 19 int color;
 20 int tim=0;
 21 int vis[maxn];
 22 void add(int x,int y)
 23 {
 24     cnt++;
 25     to[cnt]=y;
 26     next[cnt]=head[x];
 27     head[x]=cnt;
 28 }
 29 vector <int >v[maxn],all;
 30 vector <int > g[maxn];
 31 void tarjan(int x)
 32 {
 33     dfn[x]=low[x]=++tim;
 34     st[++now]=x;
 35     instack[x]=true;
 36     for(int i=head[x];i;i=next[i])
 37     {
 38           if(!dfn[to[i]])
 39           {
 40               tarjan(to[i]);
 41              low[x]=min(low[x],low[to[i]]);
 42          }
 43          else if(instack[to[i]])
 44          {
 45              low[x]=min(low[x],dfn[to[i]]);
 46          }
 47     }
 48 //    cout<<x<<" "<<low[x]<<" "<<dfn[x]<<endl;
 49     if(low[x]==dfn[x])
 50     {
 51     //    cout<<x<<endl;
 52         color++;
 53         int j=-1;
 54         small[color]=19991231;
 55         do
 56         {
 57             j=st[now--];
 58             big[color]=max(big[color],val[j]);
 59             small[color]=min(small[color],val[j]);
 60             instack[j]=false;
 61             col[j]=color;
 62         }while(x!=j);
 63     }
 64 }
 65 int out[maxn];
 66 int ans;
 67 int ss[maxn];
 68 void dfs(int x)
 69 {
 70 //    cout<<x<<endl;
 71     vis[x]=true;
 72     for(int i=0;i<g[x].size();i++)
 73     {
 74         //cout<<x<<" "<<g[x][i]<<endl;
 75         if(!vis[g[x][i]])
 76         {
 77             dfs(g[x][i]);
 78         }
 79     }
 80 }
 81 void dfss(int x)
 82 {
 83     ss[x]=true;
 84     for(int i=0;i<v[x].size();i++)
 85     {
 86         //cout<<x<<" "<<g[x][i]<<endl;
 87         if(!ss[v[x][i]])
 88         {
 89             dfss(v[x][i]);
 90         }
 91     }
 92 }
 93 int solve(int x)
 94 {
 95     //cout<<x<<" ";
 96     if(dp[x])return dp[x];
 97     dp[x]=small[x];
 98     //cout<<x<<" "<<dp[x]<<endl;
 99     for(int i=0;i<v[x].size();i++)
100     {
101         //cout<<x<<" "<<v[x][i]<<endl;
102         if(!vis[v[x][i]] || !ss[v[x][i]] )continue;
103         if(v[x][i]==x)continue;
104     //    cout<<dp[x]<<endl;
105         dp[x]=min(dp[x],solve(v[x][i]));
106     //    cout<<v[x][i]<<" "<<dp[x]<<" "<<solvedp[v[x][i]]<<endl;
107     }
108 //    cout<<x<<" "<<dp[x]<<endl;
109 //    cout<<x<<" "<<dp[x]<<" "<<big[x]<<endl;
110     if(big[x]-dp[x]>ans)ans=big[x]-dp[x];
111     //cout<<x<<" "<<ans<<endl;
112     return dp[x];
113 }
114 int main()
115 {
116     scanf("%d%d",&n,&m);
117     for(int i=1;i<=n;i++)scanf("%d",&val[i]);
118     for(int i=1;i<=m;i++)
119     {
120         int x,y,z;
121         scanf("%d%d%d",&x,&y,&z);
122         add(x,y);
123         if(z!=1)add(y,x);
124         u[i]=x;
125         h[i]=y;
126     }
127 //    cout<<endl;
128
129     for(int i=1;i<=n;i++)
130     {
131         if(!dfn[i])
132         {
133             tarjan(i);
134         }
135     }
136 //    cout<<col[1]<<endl;
137     for(int i=1;i<=m;i++)
138     {
139         if(col[u[i]]!=col[h[i]])
140         {
141         //    cout<<col[u[i]]<<" "<<col[h[i]]<<endl;
142             v[col[h[i]]].push_back(col[u[i]]);
143             g[col[u[i]]].push_back(col[h[i]]);
144         }
145     }
146 //    cout<<col[5]<<endl;
147 //    cout<<color<<endl;
148 //for(int i=1;i<=n;i++)cout<<i<<" "<<col[i]<<endl;
149     //for(int i=1;i<=color;i++)cout<<big[i]<<" "<<small[i]<<endl;
150     dfs(col[1]);
151     dfss(col[n]);
152 //    for(int i=1;i<=color;i++)cout<<i<<" "<<vis[i]<<endl;
153 //    cout<<ans<<endl;
154 //    cout<<color<<endl;
155     int tmp=solve(col[n]);
156 //    cout<<ans<<endl;
157     for(int i=1;i<=color;i++)
158     {
159         if(vis[i] && ss[i])ans=max(ans,big[i]-small[i]);
160     //    cout<<big[i]-small[i]<<endl;
161         //cout<<vis[i]<<" "<<big[i]<<" "<<small[i]<<endl;
162     }
163     if(!vis[col[n]] || !ss[col[1]])ans=0;
164 //    cout<<vis[col[n]];
165     printf("%d\n",ans);
166     return 0;
167 }

[NOIP2009提高组]最优贸易 tarjan题解

时间: 2024-10-01 12:25:51

[NOIP2009提高组]最优贸易 tarjan题解的相关文章

noip2009提高组题解

第一题:潜伏者 模拟 注意点: 不同的密文对应的明文不同,反过来,不同的明文对应的密文也不同,我用了两个hash表来实现: 26个明文字母必须有对应的密文字母,我用了两个计数变量来判断是否26个字母都有匹配. ? 第二题:Hankson的趣味题 数论 对 a0, a1, b0, b1 四个数进行质因数分解,然后确定 x 的各质因数的指数的取值范围,运用乘法原理解决.详细分析见下: (引用自http://wenwen.sogou.com/z/q169562042.htm) Gcd(x,a0)=a1

Noip2009提高组总结

Noip2009的题目还是有一定难度的,主要是搜索和最短路都是我的弱项,不检查第一遍下来只做了150分,还是这句话,素质和读题的仔细程度决定了分数.仔细想想,我们化学老师说的话没错,或许题目你都会做,但是你在考试时犯下的各种错误终将导致你的失败,所以,提高个人编程的素样,对于我来说才是目前最重要的事. T1:潜伏者 第一题是极简单的字符串操作题,读题仔细一点,注意各种规则即可AC,但是在做的时候自己犯了一点小错误,结果只有90分,这是不应该的! + ? 1 2 3 4 5 6 7 8 9 10

NOIP2009提高组解题报告

前些天做了一趟noip2009提高组的题,第一次得分为285,算是达到了那年省一的线,但也充分说明了我还存在很多问题. 第一题: [问题描述] R 国和S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动.历尽艰险后,潜伏于 S 国的R 国间谍小C 终于摸清了S 国军用密码的编码规则: 1. S 国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所 得的内容均由大写字母'A'-'Z'构成(无空格等其他字符). 2. S 国对于每个字母规定了对应的"密字".加密

[NOIP2009] 提高组 洛谷P1073 最优贸易

题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路,双向通行的道路在统计条数时也计为 1 条. C 国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价 格不一定相同.但是,同一种商品在同一个城市的买入价和卖出价始终是相同的. 商人阿龙来到 C 国旅游.当他得知同一种商品在不同城市的价格可能会不同这一信息 之后,便决定在旅游的

[NOIP2009] 提高组 洛谷P1071 潜伏者

题目描述 R 国和 S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动.历尽艰险后,潜伏于 S 国的 R 国间谍小 C 终于摸清了 S 国军用密码的编码规则: 1. S 国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容与加密后所得的内容均由大写字母‘A’-‘Z’构成(无空格等其他字符). 2. S 国对于每个字母规定了对应的“密字”.加密的过程就是将原信息中的所有字母替换为其对应的“密字”. 3. 每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”.“密字”可以

【NOIP2009提高组】最优贸易

https://www.luogu.org/problem/show?pid=1073 如果他想在i点卖出,那么就要在从1点出发到i点的路径里找个最便宜的买入,用Bellman-Ford求出这样最便宜的买入价记为minp[i].他能获得的利润就是price[i]-minp[i]. 但是并不是可以在所有的点都可以卖出,因为他最终要走到N,所以只有在和N联通的点才能卖出.用从N点出发倒着的DFS/BFS记录点i是否能到达N点. 故答案为max{price[i]-minp[i] (i点与N点联通)}

[NOIP2009][LuoguP1073] 最优贸易 - Tarjan,拓扑+DP

Description&Data 题面:https://www.luogu.org/problemnew/show/P1073 Solution Tarjan对联通块缩点,在DAG上按照拓扑序更新最低买入价,到每个点时再更新一下答案,即联通块内最大卖出价减去沿途的最低价格,复杂度O(n). 看机房其他人有写双向SPFA,代码短一些,反向建一张图,一遍跑最大一遍跑最小,最后枚举一下最优答案即可 Tarjan代码如下:(SPFA在后面) #include<iostream> #includ

P1073 最优贸易 (tarjan缩点+dp)

题目链接:https://www.luogu.com.cn/problem/P1073. C国有n n n个大城市和m mm 条道路,每条道路连接这 nnn个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 mmm 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道路在统计条数时也计为 11 1条. CC C国幅员辽阔,各地的资源分布情况各不相同,这就导致了同一种商品在不同城市的价格不一定相同.但是,同一种商品在同一个城市的买入价和卖出价始终是相同的. 商人阿

唯一分解定理的应用: NOIP2009 提高组第二题Hankson [唯一分解定理|暴力]

输入输出格式 输入格式: 第一行为一个正整数 n,表示有 n 组输入数据.接下来的 n 行每 行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开.输入 数据保证 a0 能被 a1 整除,b1 能被 b0 整除. 输出格式: 输出文件 son.out 共 n 行.每组输入数据的输出结果占一行,为一个整数. 对于每组数据:若不存在这样的 x,请输出 0: 若存在这样的 x,请输出满足条件的 x 的个数: 输入输出样例 输入样例#1: 2 41 1 96 288 95