zoukankan      html  css  js  c++  java
  • [APIO2017]商旅(分数规划,spfa)

    题面

    luogu

    题意

    n点m边有向图,k种商品,每种商品在每个点有一个售价和收购价
    (可能存在点不支持某种商品的买卖)
    同一时刻只能携带一种商品,求一个回路使得收益最大
    答案向下取整
    (1 leq N leq 100,1 leq M leq 9900, 1 leq K leq 1000)

    题解

    12opts很简单 处理出每个点到1的最短路,最大收益和从1到达的最短路即可
    开始想的是分数规划+无源汇最大费用最大流check
    两点之间的边就是在这两点做购入售出的最大收益减去mid * dis
    然后发现这个无源汇最大费用最大流要求为正数还要成环感觉没法做怎么又这么熟悉
    于是用spfa判负环就好了。。

    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <map>
    #define Dis(x, y, z) (w[x][y] - road[x][y] * z)
    using namespace std;
    const int N = 105;
    const int K = 1005;
    const long long inf = 1e18;
    int n, m, k;
    long long road[N][N], w[N][N];
    int b[N][K], s[N][K];
    inline int getmx(int x, int y){
    	int res = 0;
    	for(int i = 1; i <= k; ++i) if(~s[y][i] && ~b[x][i]) res = max(res, s[y][i] - b[x][i]);
    	return res;
    }
    queue<int> que; 
    bool vis[N];
    int cnt[N]; long long dis[N];
    inline bool check(int W){
        //printf("W = %d
    ", W);
    	memset(dis, 0, sizeof(dis));
    	while(!que.empty()) que.pop();
    	for(int i = 1; i <= n; ++i) que.push(i), vis[i] = 1, cnt[i] = 0;
    	while(!que.empty()){
    		int fro = que.front(); que.pop(); vis[fro] = 0;
    		if(++cnt[fro] > n) return 1;
    		for(int i = 1; i <= n; ++i) if(fro != i){
    			//if(road[fro][i] < inf && W < 5) printf("%d %d %lld %lld
    ", fro, i, dis[i], road[fro][i] * W - w[fro][i]);
    			if(road[fro][i] < inf && dis[i] >= dis[fro] + (road[fro][i] * W - w[fro][i])){
    				dis[i] = dis[fro] + (road[fro][i] * W - w[fro][i]);
    				if(!vis[i]) que.push(i), vis[i] = 1;
    			}
    		}
    	}
    	//printf("Yeah!
    ");
    	return 0;
    } 
    int main(){
    	scanf("%d%d%d", &n, &m, &k);
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= k; ++j)
    		    scanf("%d%d", &b[i][j], &s[i][j]);
    	for(int i = 1; i <= n; ++i){
    	    for(int j = 1; j <= n; ++j) road[i][j] = inf;
    		road[i][i] = 0;
    	}
    	for(int i = 1, x, y, z; i <= m; ++i)
    		scanf("%d%d%d", &x, &y, &z), road[x][y] = z;
    	for(int p = 1; p <= n; ++p)
    	    for(int i = 1; i <= n; ++i) if(i != p)
    	        for(int j = 1; j <= n; ++j) if(j != i && j != p){
    	            road[i][j] = min(road[i][j], road[i][p] + road[p][j]);	
    	        }
    	for(int i = 1; i <= n; ++i)
    	    for(int j = 1; j <= n; ++j)
    	        w[i][j] = getmx(i, j);
    	int l = 0, r = 1e9, mid, ret;
    	while(l < r){
    		mid = l + ((r - l + 1) >> 1);
    		if(check(mid)) l = mid;
    		else r = mid - 1;
    	}
    	printf("%d
    ", l);
    	return 0;
    }
    
  • 相关阅读:
    我从来没有想要去
    微信公众号开发系列-发展模式,创建自己的自定义菜单
    iOS6之后 NSAttributedString 福利
    iOS 面试题:OC标题的基本概念&lt;延续&gt;
    逻辑、认识论和本体论“三统一”
    C++中的头文件和源文件
    extern与头文件(*.h)的区别和联系
    Predicate Format String Syntax 与字面量
    编码、格式与网络通信
    充分条件和必要条件的联系和区别是什么
  • 原文地址:https://www.cnblogs.com/hjmmm/p/10808785.html
Copyright © 2011-2022 走看看