题目大意:
n个点,m条边
在n个点有一个物品买入和卖出的价值
m条边中保证x<y(连接的两个点)
问 对一个物品买卖一次的最大利润是多少
Solution 1:
因为边中保证了x<y,所以可以看出有向无环图
mi[]定义为到达i点之前(不包括i点)的最小出买卖值
那么如果在i点进行交易的话,得到的利润为 val[i] - mi[i]
只需要枚举每个点 更新答案
然后用每个点的边集再更新一边 mi数组
复杂度O(N+M)
Solution 2:
如果题目的边中不保证x<y,是一个普通的有向图
对所有的点的买卖价值升序排列
选最便宜的点,然后进行bfs列举他能够到达的所有点
更新答案
ans = max(ans,val[u]-minn1)
然后选第二便宜的点
重复上述操作
走过的点可以不用再走
因为先选的minn1 所能够达到的点
如果minn2所能够到达的点中和minn1到达的点中有相同的点,那么一定是minn1更优
所以minn2的再次经过时可以忽略
Code1:
ll n,m,val[maxn];
vector<ll>e[maxn];
ll ans=-inf,mi[maxn];
int main() {
n=read(),m=read();
rep(i,1,n) val[i] = read(),mi[i] = inf;
for(int i=1 ; i<=m ; i++) {
int u,v;
u=read(),v=read();
e[u].push_back(v);
}
for(int i=1 ; i<=n ; i++) {
ans = max(ans,val[i] - mi[i]);
mi[i] = min(mi[i],val[i]);
for(int j:e[i]) {
mi[j] = min(mi[j],mi[i]);
}
}
out(ans);
return 0;
}
Code2:
int n,m,ans=-inf,vis[maxn],val[maxn];
vector<int>e[maxn];
struct node {
int num,id;
} a[maxn];
bool cmp(node x,node y) {
return x.num<y.num;
}
void bfs(int st) {
queue<int>q;
q.push(a[st].id);
while(q.size()) {
int fr =q.front();
q.pop();
for(int v:e[fr]) {
if(vis[v]) continue;
vis[v]=1;
ans = max(ans,val[v] - a[st].num);
q.push(v);
}
}
}
int main() {
n=read(),m=read();
for(int i=1 ; i<=n ; i++) {
a[i].id = i;
val[i] = a[i].num = read();
}
sort(a+1,a+1+n,cmp);
for(int i=1 ; i<=m ; i++) {
int u,v;
u=read(),v=read();
e[u].push_back(v);
}
for(int i=1 ; i<=n ; i++) {
if(vis[i]) continue;
bfs(i);
}
out(ans);
return 0;
}