【luogu1073】最优贸易(队列)

来源:互联网 发布:怎么把知乎转到微信 编辑:程序博客网 时间:2024/05/16 09:37

题目:

我是超链接

题解:

很有意思的题目,仿佛很麻烦的样子需要dp,但是我们可以发现简单的队列模拟就可以过啦

f[i]表示到i点最大赚取旅费,g[i]表示到i的最小买入价格,类似SPFA遍历边,f可更新就更新f,g可更新就更新g,不管更新了哪一个,都可以加在队列里继续更新啦

代码:

#include <cstdio>#include <queue>#include <iostream>#include <cstring>#define N 100005#define M 1000005using namespace std;int f[N],g[N],tot,nxt[M],point[M],v[M],w[N];bool c[N];//f[i]表示到i点最大赚取旅费,g[i]表示到i的最小买入价格 void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}int main(){int n,m,i;scanf("%d%d",&n,&m);for (i=1;i<=n;i++)  scanf("%d",&w[i]);for (i=1;i<=m;i++){int x,y,z;scanf("%d%d%d",&x,&y,&z);if (z==1) addline(x,y);else addline(x,y),addline(y,x);}queue<int>q;memset(c,0,sizeof(c)); c[1]=1;memset(f,0,sizeof(f));memset(g,0x7f,sizeof(g)); g[1]=w[1];q.push(1);    while (!q.empty())    {    int now=q.front(); q.pop();    c[now]=false;    for (i=point[now];i;i=nxt[i])      if (f[v[i]]<max(f[now],w[v[i]]-g[now]) || g[v[i]]>min(g[now],w[v[i]]))      {      f[v[i]]=max(max(f[v[i]],f[now]),w[v[i]]-g[now]);      g[v[i]]=min(min(g[now],g[v[i]]),w[v[i]]);      if (!c[v[i]]) c[v[i]]=true,q.push(v[i]);  }}printf("%d",f[n]);}