首页 > 代码库 > [NOIP2009提高组]最优贸易 tarjan题解

[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