博客
关于我
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 Join算法与调优白皮书(二)
查看>>
Mysql order by与limit混用陷阱
查看>>
Mysql order by与limit混用陷阱
查看>>
mysql order by多个字段排序
查看>>
MySQL Order By实现原理分析和Filesort优化
查看>>
mysql problems
查看>>
mysql replace first,MySQL中处理各种重复的一些方法
查看>>
MySQL replace函数替换字符串语句的用法(mysql字符串替换)
查看>>
mysql replace用法
查看>>
Mysql Row_Format 参数讲解
查看>>
mysql select, from ,join ,on ,where groupby,having ,order by limit的执行顺序和书写顺序
查看>>
MySQL Server 5.5安装记录
查看>>
mysql server has gone away
查看>>
mysql slave 停了_slave 停止。求解决方法
查看>>
MySQL SQL 优化指南:主键、ORDER BY、GROUP BY 和 UPDATE 优化详解
查看>>
MYSQL sql语句针对数据记录时间范围查询的效率对比
查看>>
mysql sum 没返回,如果没有找到任何值,我如何在MySQL中获得SUM函数以返回'0'?
查看>>
mysql Timestamp时间隔了8小时
查看>>
Mysql tinyint(1)与tinyint(4)的区别
查看>>
mysql union orderby 无效
查看>>