[APIO2017]商旅 0/1分数规划
题解:
upd: 在洛谷上被Hack了。。。思路应该是对的,代码就别看了
感觉有个地方还是非常妙的,就是因为在x买东西,在y卖出,就相当于直接从x走向了y,因为经过中间的城市反正也不会造成任何影响。
所以建图就可以直接把所有城市两两连边,然后直接枚举找出使得在x买东西,在y卖出的利润最大化的物品,并将利润作为权值,(a[i])
再floyd找出x到y的最短路径(这大概就算用到城市可以重复经过的条件了吧)作为代价,(b[i])
接下来就和[HNOI2009]最小圈非常类似了。
只不过这里是要找最大利润,而我们是用spfa找负环,所以可以对边权取相反数,(当然你也可以不变边权找正环)
此外还有一个需要注意的地方,
如果你是二分小数自然没有任何问题,
但是如果你是二分整数就要注意判断0环了(因为答案是向下取整的),因为如果你二分小数的话,反正你会多二分几次来保证精度,所以不判断是没有什么问题的,
但是整数不一样,所以要判断0环,方法也很简单,在dfs版spfa里面的判断条件上加上=就可以了
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 150
#define ac 21000
#define getchar() *o++
#define inf 2139062143
char READ[],*o=READ;
int n,m,l,mid,maxn;
int buy[AC][AC*],sale[AC][AC*],s[AC][AC],f[AC][AC],dis[ac];
int date[ac],Next[ac],Head[AC],length[ac],tot;
bool vis[AC],flag;
/*想了很久如何处理异地交易的问题,因为中间走过的路程会被忽略,
所以实际上就相当于直接从买入地x走到了卖出地y,
所以直接两两连边,因为反正可以重复经过,所以走一条边就相当于略过了中间的所有边,
然后为了尽量节省时间,所以先处理出任意两点之间的最短路,因为不管怎么走收益不变,
但代价变了,所以连边要连最短路,所以先floyd处理一下,再把结果连成边,
不过利益不变的前提是买同一种商品,但是商品不止一种,所以还要处理出最大收益,
因为地点都已经固定了,所以这个时候就只要枚举一下买哪种划得来了,
标准就是买卖单个的收入就行了
然后动态改一下权值就好了,dfs版spfa找负环*/
inline int read()
{
int x=;char c=getchar();bool z=false;
while(c > '' || c < '') {if(c == '-') z=true; c=getchar();}
while(c >= '' && c <= '') x=x*+c-'',c=getchar();
if(!z) return x;
else return -x;
} inline void add(int f,int w)
{
date[++tot]=w,Next[tot]=Head[f],Head[f]=tot;
} inline void upmin(int &a,int b)
{
if(b < a) a = b;
} inline void upmax(int &a,int b)
{
if(b > a) a = b;
} void pre()
{
int a,b,c;
n=read(),m=read(),l=read();
memset(f,,sizeof(f));
for(R i=;i<=n;i++)
{
f[i][i]=;
for(R j=;j<=l;j++)
buy[i][j]=read() , sale[i][j]=read();
}
for(R i=;i<=m;i++)
{
a=read(),b=read(),c=read();
upmin(f[a][b],c);//这里就要upmin。,,,,不然可能会被不优的边覆盖
}
} void init()
{
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",f[i][j]);
printf("\n");
}
printf("!!!\n");*/
for(R k=;k<=n;k++)
for(R i=;i<=n;i++)
{
if(f[i][k] == inf) continue;
for(R j=;j<=n;j++)
if(f[k][j] != inf) upmin(f[i][j] , f[i][k] + f[k][j]);
}//怕爆了
for(R i=;i<=n;i++)//枚举起点
for(R j=;j<=n;j++)//枚举终点
{
if(i == j) continue;
if(f[i][j] == inf) continue;
for(R k=;k<=l;k++) //枚举买哪种
{
if(sale[j][k] == - || buy[i][k] == -) continue;
upmax(s[i][j],sale[j][k] - buy[i][k]);//获取利润
upmax(maxn,s[i][j] / f[i][j]);
}
}
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",f[i][j]);
printf("\n");
}
// printf("---------------\n");
printf("\n");
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",s[i][j]);
printf("\n");
}*/
for(R i=;i<=n;i++)
for(R j=;j<=n;j++)
{
if(i == j) continue;
if(f[i][j] == inf) continue;//error,,,这里不能加上!s[i][j],虽然没有利润,但仍然可以起到连接作用
add(i,j);
}
} void spfa(int x)
{
int now;
vis[x]=true;
for(R i=Head[x]; i ;i=Next[i])
{
now=date[i];
if(dis[now] >= dis[x] + length[i])//找负环肯定是最短路啊
{//加个等号判0环?
if(vis[now]) {flag=true;break;}
dis[now] = dis[x] + length[i];
spfa(now);
}
}
vis[x]=false;
} bool check()
{
int now;
flag=false;
memset(dis,,sizeof(dis));
for(R i=;i<=n;i++)
for(R j=Head[i]; j ;j=Next[j])
{
now=date[j];
length[j]=mid * f[i][now] - s[i][now];//因为要用找负环的方法找正环,所以边权取相反
}//error,,是f[i][now]
for(R i=;i<=n;i++)
{
spfa(i);
if(flag) return true;
}
return false;
} void half()
{
int l=,r=maxn;
while(r - l > )
{
mid=(l + r) / ;
if(check()) l=mid;
else r=mid;
}
if(r > l)
{
mid=r;
if(check()) printf("%d\n",r);
else printf("%d\n",l);
}
else printf("%d\n",l);
} int main()
{
// freopen("in.in","r",stdin);
fread(READ,,,stdin);
pre();
init();
half();
// fclose(stdin);
return ;
}
[APIO2017]商旅 0/1分数规划的更多相关文章
- bzoj 4898: [Apio2017]商旅【Floyd+分数规划+二分】
其实并不会分数规划 因为要最大化 ans=总收益/总路程 ,所以考虑二分答案,找到一条 ans<=总收益/总路程 的回路.先预处理出d(i,j)为(i,j)最短路,w(i,j)为在i买某个物品在 ...
- [APIO2017]商旅(floyd+分数规划+SPFA)
题解:首先肯定要跑最短路,而n<=100,所以可以用floyd,然后根据比值,很容易想到二分答案,然后再SPFA跑一遍负环,就能求出解了. #include<bits/stdc++.h&g ...
- poj 2976 Dropping tests 0/1分数规划
0/1分数规划问题,用二分解决!! 代码如下: #include<iostream> #include<stdio.h> #include<algorithm> # ...
- bzoj 3597: [Scoi2014]方伯伯运椰子 0/1分数规划
3597: [Scoi2014]方伯伯运椰子 Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 144 Solved: 78[Submit][Status ...
- LOJ 3089 「BJOI2019」奥术神杖——AC自动机DP+0/1分数规划
题目:https://loj.ac/problem/3089 没想到把根号之类的求对数变成算数平均值.写了个只能得15分的暴力. #include<cstdio> #include< ...
- poj2728 Desert King【最优比率生成树】【Prim】【0/1分数规划】
含[最小生成树Prim]模板. Prim复杂度为$O(n^2),适用于稠密图,特别是完全图的最小生成树的求解. Desert King Time Limit: 3000MS Memory Li ...
- POJ - 2976 Dropping tests && 0/1 分数规划
POJ - 2976 Dropping tests 你有 \(n\) 次考试成绩, 定义考试平均成绩为 \[\frac{\sum_{i = 1}^{n} a_{i}}{\sum_{i = 1}^{n} ...
- [SDOI2017]新生舞会 0/1分数规划
---题面--- 题解: 0/1分数规划,,,但是竟然有诡异的精度问题???因为这个被卡了好久 中途还写过一次KM,,,结果陷入死循环,,,我大概是写了一个假KM,,,于是放弃KM,回来调费用流 这个 ...
- bzoj3232圈地游戏——0/1分数规划+差分建模+判环
Description DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用. DZY喜欢在地里散步.他总是从任意一个格点出发,沿着格线行走直到 ...
随机推荐
- 函数返回const,以便控制访问
#include <stdio.h> class const_out_parameter{ private: ]; public: int* const_out_parameter_tes ...
- OpenCV 3.0.0处理鱼眼镜头信息 - Fisheye camera model
此篇随笔主要参考OpenCV 3.0.0的官方文档翻译而来,主要用作理解OpenCV对鱼眼相机的标定.图像校正.3D重建功能的理解. 版权所有,转载请注明出处~ xzrch@2018.09.29 参考 ...
- OSG-基本几何图形
本文转至http://www.cnblogs.com/shapherd/archive/2010/08/10/osg.html 作者写的比较好,再次收藏,希望更多的人可以看到这个文章 互联网是是一个相 ...
- lesson 24 A skeleton in the cupboard
lesson 24 A skeleton in the cupboard conceal sth from sb 对某人隐藏某事 He conceals his girlfriend from his ...
- javac 编译过程
javac 编译过程 一.解析与填充符号表: 1. 语法.此法分析: a) 语法分析:将源代码字符流转换为标记(Token:编译过程最小元素)集合. b) ...
- [CF294B]Shaass and Bookshelf
问题描述 Shaass拥有n本书.他想为他的所有书制作一个书架,并想让书架的长宽尽量小.第i本书的厚度是t[i],且这本书的纸张宽度是w[i].书的厚度是1或2,所有书都有同样的高度(即书架的高是均匀 ...
- Struts2(九.初始化用户列表时显示用户照片数目)
1.userlist.jsp //显示每个用户照片的数目(遍历每个用户) $(".picture").each(function(i,e){ $.post("${page ...
- some Commands OF CONSOLE
不可避免地使用console,一旦与电脑打交道:入口就是help,而很多行就直接过掉了,却不能看到需要的地方,在那里停下来,实际是需要使用more less grep等 在windows中,使用di ...
- 【转载】inotify+rsync实时同步 解决同步慢问题 (转载备记)
原文地址:http://www.ttlsa.com/web/let-infotify-rsync-fast/ 背景 我们公司在用inotify+rsync做实时同步,来解决分布式集群文件一致性的问题. ...
- 转:Linux 编译安装 Mysql5.7
http://broqiang.com/2017/04/18/Mysql-Install-5.7.18-Linux-Compile/ 原文 Linux 编译安装 Mysql5.7 Ubuntu 下快速 ...