博客
关于我
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灵魂拷问:36题带你面试通关
查看>>
mysql状态分析之show global status
查看>>
mysql状态查看 QPS/TPS/缓存命中率查看
查看>>
mysql生成树形数据_mysql 实现树形的遍历
查看>>
mysql用于检索的关键字_Mysql全文搜索match...against的用法
查看>>
MySQL用得好好的,为什么要转ES?
查看>>
MySql用户以及权限的管理。
查看>>
MySQL用户权限配置:精细控制和远程访问的艺术!------文章最后有惊喜哦。
查看>>
mysql用户管理、常用语句、数据分备份恢复
查看>>
MySQL留疑问:left join时选on还是where?
查看>>
mysql登陆慢问题解决
查看>>
Mysql百万级数据查询优化
查看>>
MySQL的 DDL和DML和DQL的基本语法
查看>>
mysql的 if else , case when then, IFNULL
查看>>
MySQL的10种常用数据类型
查看>>
MySQL的btree索引和hash索引的区别
查看>>
mysql的cast函数
查看>>
MySql的CRUD(增、删、改、查)操作
查看>>
MySQL的DATE_FORMAT()函数将Date转为字符串
查看>>
mysql的decimal与Java的BigDecimal用法
查看>>