• 【bzoj4898】[Apio2017]商旅 Floyd+分数规划+Spfa


    题目描述

    有n个点、m条边、和k种商品。第$i$个点可以以$B_{ij}$的价格买入商品$j$,并以$S_{ij}$的价格卖出。任何时候只能持有一个商品。求一个环,使得初始不携带商品时以某种交易方式走过一圈所得的利润/路径长度(向下取整)最大。

    输入

    第一行包含3个正整数N,M和K,分别表示集市数量、道路数量和商品种类数量。
    接下来的N行,第行中包含2K个整数描述一个集市Bi,1 Si,1 Bi,2 Si,2...Bik Si,k。
    对于任意的1<=j<=k,整数和分别表示在编号为的集市上购买、卖出编号为的商品时的交易价格。
    如果一个交易价格为-1,则表示这个商品在这个集市上不能进行这种交易。
    接下来M行,第行包含3个整数Vp,Wp和Tp,表示存在一条从编号为Vp的市场出发前往编号为Wp的市场的路径花费Tp分钟。
    1<=N<=100,1<=M<=9900
    如果在编号为的集市i中,编号为j的商品既可以购买又可以卖出则0<Si,j<=Bi,j<=10^9
    对于编号为P(1<=P<=M)的道路,保证Vp<>Wp且1<=Tp<=10^7
    不存在满足1<=P<Q<=M的P,Q,使得(Vp,Wp)=(Vq,Wq) 。

    输出

    输出包含一个整数,表示盈利效率最高的环路盈利效率,答案向下取整保留到整数。如果没有任何一条环路可以盈利,则输出0。

    样例输入

    4 5 2
    10 9 5 2
    6 4 20 15
    9 7 10 9
    -1 -1 16 11
    1 2 3
    2 3 3
    1 4 1
    4 3 1
    3 1 1

    样例输出

    2


    题解

    Floyd+分数规划+Spfa

    题目显然是一个分数规划的模型,但是如果直接使用分层图模拟商品买卖的过程的话肯定会TLE。

    我们不妨换个思路:考虑每件两点之间的连续交易。即在A地购买商品,并在B地卖出的这个过程。

    那么这个过程走的一定是最短路,买卖的一定是盈利最大的商品(当无法盈利时显然不进行买卖,盈利为0)。

    所以可以使用Floyd求出任意两点之间最短路,再处理出来任意两点之间的最大盈利。

    然后就可以对这个图求最大比率环了。二分答案,把每条边的权值看作 最大盈利-最短路*mid ,如果有非负环则说明mid成立,否则mid不成立。

    时间复杂度$O(n^2k+n^3log v)$。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #define N 110
    #define K 1010
    using namespace std;
    typedef long long ll;
    queue<int> q;
    int n , len[N][N] , val[N][N] , b[N][K] , s[N][K] , inq[N] , num[N];
    ll dis[N];
    inline bool judge(int mid)
    {
    	int x , i;
    	while(!q.empty()) q.pop();
    	for(i = 1 ; i <= n ; i ++ ) dis[i] = inq[i] = num[i] = 0 , q.push(i);
    	while(!q.empty())
    	{
    		x = q.front() , q.pop() , inq[x] = 0;
    		for(i = 1 ; i <= n ; i ++ )
    		{
    			if(dis[i] <= dis[x] + val[x][i] - (ll)mid * len[x][i])
    			{
    				dis[i] = dis[x] + val[x][i] - (ll)mid * len[x][i];
    				if(!inq[i])
    				{
    					if(num[i] == n) return 1;
    					num[i] ++ , inq[i] = 1 , q.push(i);
    				}
    			}
    		}
    	}
    	return 0;
    }
    int main()
    {
    	int m , p , i , j , k , x , y , z , l = 1 , r = 0 , mid , ans = 0;
    	scanf("%d%d%d" , &n , &m , &p);
    	for(i = 1 ; i <= n ; i ++ )
    		for(j = 1 ; j <= p ; j ++ )
    			scanf("%d%d" , &b[i][j] , &s[i][j]);
    	for(i = 1 ; i <= n ; i ++ )
    		for(j = 1 ; j <= n ; j ++ )
    			for(k = 1 ; k <= p ; k ++ )
    				if(~b[i][k] && ~s[j][k])
    					val[i][j] = max(val[i][j] , s[j][k] - b[i][k]);
    	memset(len , 0x3f , sizeof(len));
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , len[x][y] = z , r = max(r , z);
    	for(k = 1 ; k <= n ; k ++ )
    		for(i = 1 ; i <= n ; i ++ )
    			for(j = 1 ; j <= n ; j ++ )
    				len[i][j] = min(len[i][j] , len[i][k] + len[k][j]);
    	while(l <= r)
    	{
    		mid = (l + r) >> 1;
    		if(judge(mid)) ans = mid , l = mid + 1;
    		else r = mid - 1;
    	}
    	printf("%d
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    OneNote 2010 文字识别
    Windows 7 添加网络共享打印机
    logstash
    filebeat
    记elk打包时的问题
    elasticsearch.yml
    zabbix 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作
    mac装brew
    snmp监控
    博科光纤交换机端口别名映射脚本
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7570573.html
Copyright © 2020-2023  润新知