博客
关于我
P1073 最优贸易(SPFA)
阅读量:394 次
发布时间:2019-03-05

本文共 2335 字,大约阅读时间需要 7 分钟。

最优贸易

NOIP 2009 提高组 第三题

题目大意

有n个点,有m个通道(有向或无向)。他要找到一条路,点可以重复出现。在路上,买水晶球再卖掉水晶球,最后到n点。要求出他最大能赚多少钱(用卖水晶球的钱减买水晶球的钱
分析
复杂的分析
在这里插入图片描述下面深入理解
可以用两个spfa算法
邻接表建立,如图:
在这里插入图片描述从1点去找,找到能到的点,并且赋值给他们:买水晶球最小的钱

void spfa1(int o){   	minn[o]=w[o];//初值    head=0;tail=1;	b[1]=o;c[o]=1;    do    {           head=head%N+1;//循环队列,否则会炸        int k=b[head];//方便        for(int i=head1[k];i;i=a1[i].next)         if(minn[a1[i].to]>min(minn[k],w[a1[i].to]))//松弛算法          {               minn[a1[i].to]=min(minn[k],w[a1[i].to]);            if(c[a1[i].to]==0)//是否标记过,没有就将这个数进入队列             {               	tail++;            	b[tail]=a1[i].to;            	c[a1[i].to]=1;             }          }    	c[k]=0;    }while(head

下面的需要将邻接表倒置,如图

在这里插入图片描述
从n点去找,找到能到的点,并且赋值给他们:卖水晶球最大的钱

void spfa2(int o){   	maxn[o]=w[o];//初值    head=0;tail=1;	b[1]=o;c[o]=1;    do    {           head=head%N+1;//循环队列,否则炸        int k=b[head];//方便        for(int i=head2[k];i;i=a2[i].next)         if(maxn[a2[i].to]

注意:复制后要仔细修改一些细节

最后,从2点到(n-1)点进行枚举,找到同一个点,让它的卖水晶球减卖水晶球的钱最多(不包括起点和终点)

for(int i=2;i<=n-1;i++)//找最大赚的钱	 m=max(m,maxn[i]-minn[i]);

这个点得出的值就是结果

AC代码

#include
using namespace std;#define N 1000005#define M 5000005int n,m,x,y,z,tot1,tot2,head,tail,b[M],c[N],w[N],head1[M],head2[M],maxn[N],minn[N];struct stu{ int to,next,w;}a1[M],a2[M];void add1(int x,int y)//邻接表1号{ tot1++; a1[tot1].to=y; a1[tot1].next=head1[x]; head1[x]=tot1;}void add2(int x,int y)//邻接表2号(要倒置){ tot2++; a2[tot2].to=y; a2[tot2].next=head2[x]; head2[x]=tot2;}void spfa1(int o){ minn[o]=w[o];//初值 head=0;tail=1; b[1]=o;c[o]=1; do { head=head%N+1;//循环队列,否则会炸 int k=b[head];//方便 for(int i=head1[k];i;i=a1[i].next) if(minn[a1[i].to]>min(minn[k],w[a1[i].to]))//松弛算法 { minn[a1[i].to]=min(minn[k],w[a1[i].to]); if(c[a1[i].to]==0)//是否标记过,没有就将这个数进入队列 { tail++; b[tail]=a1[i].to; c[a1[i].to]=1; } } c[k]=0; }while(head
>n>>m; for(int i=1;i<=n;i++) { cin>>w[i];//每个地方的买和卖水晶球的钱 minn[i]=2147483647;//赋大值 } for(int i=1;i<=m;i++) { cin>>x>>y>>z; add1(x,y); add2(y,x); if(z==2)add1(y,x);//双向 if(z==2)add2(x,y);//双向 } spfa1(1); for(int i=1;i<=n;i++)//清零 c[i]=0; spfa2(n); m=0; for(int i=2;i<=n-1;i++)//找最大赚的钱 m=max(m,maxn[i]-minn[i]); cout<

谢谢

转载地址:http://tqpzz.baihongyu.com/

你可能感兴趣的文章
mysql 导入 sql 文件时 ERROR 1046 (3D000) no database selected 错误的解决
查看>>
mysql 导入导出大文件
查看>>
MySQL 导出数据
查看>>
mysql 将null转代为0
查看>>
mysql 常用
查看>>
MySQL 常用列类型
查看>>
mysql 常用命令
查看>>
Mysql 常见ALTER TABLE操作
查看>>
MySQL 常见的 9 种优化方法
查看>>
MySQL 常见的开放性问题
查看>>
Mysql 常见错误
查看>>
mysql 常见问题
查看>>
MYSQL 幻读(Phantom Problem)不可重复读
查看>>
mysql 往字段后面加字符串
查看>>
mysql 快速自增假数据, 新增假数据,mysql自增假数据
查看>>
Mysql 批量修改四种方式效率对比(一)
查看>>
Mysql 报错 Field 'id' doesn't have a default value
查看>>
MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
查看>>
Mysql 拼接多个字段作为查询条件查询方法
查看>>
mysql 排序id_mysql如何按特定id排序
查看>>