luogu P1073 最优贸易
Posted cnyali-xwx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1073 最优贸易相关的知识,希望对你有一定的参考价值。
蒟蒻的第一篇题解,大佬们轻喷(瑟瑟发抖
言归正传,这道题
看见题解区大佬们用各式各样的神仙算法切了这道题,小蒟蒻表示并不会那么多神仙算法,于是乎就水一发题解来谈谈自己的做法.
算法: Tarjan + 拓扑排序 + DP
思路: 看见这道题首先就想到tarjan缩点(我不会告诉你这是因为我只会tarjan,tarjan之后是有向无环图,自然而然可以想到在拓扑排序上dp,于是这道题的大体思路就出来了.
第一步tarjan缩点
void tarjan(int u)
dfn[u]=low[u]=++num;
s[++temp]=u;
for(int i=head[u];i;i=e[i].next)
int v=e[i].to;
if(!dfn[v])
tarjan(v);
low[u]=min(low[u],low[v]);
else if(!color[v]) low[u]=min(low[u],low[v]);
if(dfn[u]==low[u])
color[u]=++sum;
ma[sum]=max(ma[sum],cost[u]);//维护强连通分量中最大的商品价格
mi[sum]=min(mi[sum],cost[u]);//维护强连通分量中最小的商品价格
while(s[temp]!=u)
ma[sum]=max(ma[sum],cost[s[temp]]);
mi[sum]=min(mi[sum],cost[s[temp]]);//同上
color[s[temp--]]=sum;
--temp;
第二步拓扑排序+DP
dp的状态转移方程还是挺容易想的吧.
dp[to]=maxma[to]-mi[k]
这里to代表的是将要搜到的点,mi[k]代表的是此条路径上商品价格的最小值
inline void tuopu()
queue<int> q;
q.push(color[1]);
ans[color[1]]=ma[color[1]]-mi[color[1]];
while(!q.empty())
int u=q.front();
q.pop();
for(int i=head[u];i;i=ne[i].next)
int v=ne[i].to;
--rd[v];
mi[v]=min(mi[v],mi[u]);//维护路径上经过的最小值
ans[v]=max(ans[u],ma[v]-mi[v]);//dp状态转移
if(!rd[v]) q.push(v);
到这里此题的关键性代码就解决了
下面放总代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define INF 2e9+11;
using namespace std;
const int N=100000+11;
const int M=500000+11;
int n,m,sum,num,temp,tot;
int head[N],dfn[N],low[N],s[N],color[N],ma[N],mi[N],cost[N],rd[N],ans[N];
struct Edge
int from,next,to;
e[M],ne[M];
inline void read(int &a)
a=0;
char c=getchar();
while(c>57 or c<48)c=getchar();
while(47<c and c<58)
a=a*10+c-48;
c=getchar();
inline int max(int x,int y)return x > y ? x : y;
inline int min(int x,int y)return x > y ? y : x;
inline void add_edge(int from,int to)
e[++tot].next=head[from];
e[tot].from=from;
e[tot].to=to;
head[from]=tot;
//链式前向星建边
void tarjan(int u)
dfn[u]=low[u]=++num;
s[++temp]=u;
for(int i=head[u];i;i=e[i].next)
int v=e[i].to;
if(!dfn[v])
tarjan(v);
low[u]=min(low[u],low[v]);
else if(!color[v]) low[u]=min(low[u],low[v]);
if(dfn[u]==low[u])
color[u]=++sum;
ma[sum]=max(ma[sum],cost[u]);
mi[sum]=min(mi[sum],cost[u]);
while(s[temp]!=u)
ma[sum]=max(ma[sum],cost[s[temp]]);//维护强连通分量中最大的商品价格
mi[sum]=min(mi[sum],cost[s[temp]]);//维护强连通分量中最小的商品价格
color[s[temp--]]=sum;
--temp;
inline void tuopu()
queue<int> q;
q.push(color[1]);
ans[color[1]]=ma[color[1]]-mi[color[1]];
while(!q.empty())
int u=q.front();
q.pop();
for(int i=head[u];i;i=ne[i].next)
int v=ne[i].to;
--rd[v];
mi[v]=min(mi[v],mi[u]);//维护路径上经过的最小值
ans[v]=max(ans[u],ma[v]-mi[v]);//dp状态转移
if(!rd[v]) q.push(v);
int main()
read(n);read(m);
for(int i=1;i<=n;++i) read(cost[i]);
int x,y,z;
for(int i=1;i<=m;++i)
read(x);read(y);read(z);
if(z&1) add_edge(x,y);
else
add_edge(x,y);
add_edge(y,x);
for(int i=1;i<=n;++i) mi[i]=INF;//初始化mi数组
for(int i=1;i<=n;++i)
if(!dfn[i]) tarjan(i);
tot=0;
memset(head,0,sizeof(head));
for(int i=1;i<=m;++i)
if(color[e[i].from]!=color[e[i].to])
++rd[color[e[i].to]];
ne[++tot].next=head[color[e[i].from]];
ne[tot].to=color[e[i].to];
head[color[e[i].from]]=tot;
//缩点之后的新图建边
tuopu();
printf("%d",ans[color[n]]);
return 0;
如果有不懂的地方可以私信我,如果哪里有错误欢迎大佬来指正(欢迎各路神仙来吊打我
以上是关于luogu P1073 最优贸易的主要内容,如果未能解决你的问题,请参考以下文章