博客
关于我
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中的concat()相关函数
查看>>
mysql中的concat函数,concat_ws函数,concat_group函数之间的区别
查看>>
MySQL中的count函数
查看>>
MySQL中的DB、DBMS、SQL
查看>>
MySQL中的DECIMAL类型:MYSQL_TYPE_DECIMAL与MYSQL_TYPE_NEWDECIMAL详解
查看>>
MySQL中的GROUP_CONCAT()函数详解与实战应用
查看>>
MySQL中的IO问题分析与优化
查看>>
MySQL中的ON DUPLICATE KEY UPDATE详解与应用
查看>>
mysql中的rbs,SharePoint RBS:即使启用了RBS,内容数据库也在不断增长
查看>>
mysql中的undo log、redo log 、binlog大致概要
查看>>
Mysql中的using
查看>>
MySQL中的关键字深入比较:UNION vs UNION ALL
查看>>
mysql中的四大运算符种类汇总20多项,用了三天三夜来整理的,还不赶快收藏
查看>>
mysql中的字段如何选择合适的数据类型呢?
查看>>
MySQL中的字符集陷阱:为何避免使用UTF-8
查看>>
mysql中的数据导入与导出
查看>>
MySQL中的时间函数
查看>>
mysql中的约束
查看>>
MySQL中的表是什么?
查看>>
mysql中穿件函数时候delimiter的用法
查看>>