[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 }
View Code

 

posted @ 2014-08-12 14:51  溪桥,吾愿  阅读(265)  评论(0编辑  收藏  举报