《算法竞赛·快冲300题》每日一题:“花费与流量”

算法竞赛·快冲300题》将于2024年出版,是《算法竞赛》的辅助练习册。
所有题目放在自建的OJ New Online Judge
用C/C++、Java、Python三种语言给出代码,以中低档题为主,适合入门、进阶。


花费与流量” ,链接: http://oj.ecustacm.cn/problem.php?id=1717

题目描述

【题目描述】 给你一张n个点,m条边的无向图。第i条边需要花费ci元,同时流量为fi。
  现在希望购买一条路径使得1到n连通。
  路径花费X等于路径上所有边的花费。
  路径流量Y等于路径上所有边的最小流量。
  请最大化X与Y之比。。
【输入格式】 输入第一行包含n和m(2≦N≦1000,1≦M≦1000)
接下来m行,每行四个整数为u,v,c,f,分别表示边的两端点、花费和流量。(1≦c,f≦1000)。
【输出格式】 输出比值乘以1000000的值,向下取整。
【输入样例】

3 2
2 1 2 4
2 3 5 3

【输出样例】

428571

题解

  题目所求的不是简单的最短路。每条边有2个属性:花费、流量。一条路径的总花费是路径上所有边的花费之和;而一条路径的流量等于路径上所有边中最小的流量。样例中,点1到点3的路径花费是2+5=7,流量是min(4,3)=3,比值是3*1000000/7=428571。
  本题是“有流量约束的最短路径”。由于题目中的图不大,可以用暴力的方法找最大比值。
  逐一遍历m个边的流量,对每个流量做一次dijkstra,也就是保留图上大于等于这个流量的边,然后求1到n的最短路。然后求在所有X与Y之比中,找最大的哪个。
  做一次Dijkstra的复杂度是nlogn,一共做m次,总复杂度为mnlogn。
  本题的Dijkstra代码基本上是抄了模板。如果不太了解Dijkstra,请看教材。
【重点】 掌握基本的Dijkstra代码。

C++代码

  下面的代码用链式前向星存图。
  dijkstra()和模板差不多,只是加上了流量约束。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1010;
int n, m;
int head[N], e[N*2], nex[N*2], w[N*2], f[N*2], cnt;     //链式前向星存图
int flow[N];                                            //记录所有的流
int dist[N];                                            //dist[i]: 起点到i的路径长度
bool done[N];                                           //done[i]=true: 到i的最短路已经找到
void add(int a,int b, int c, int d){
    
                        //用链式前向星存图
    e[cnt] = b, w[cnt] = c, f[cnt] = d, nex[cnt] = head[a], head[a] = cnt++;
}
int dijkstra(int x){
    
    
    memset(dist, 0x3f3f3f3f, sizeof dist);
    memset(done, 0, sizeof done);
    dist[1] = 0;                                         //1到1的距离为0
    priority_queue<PII,vector<PII>,greater<PII>> q;
    q.push({
    
    0, 1});
    while(!q.empty()){
    
    
        auto t = q.top();
        q.pop();
        int d = t.first, u = t.second;
        if(done[u]) continue;                           //丢弃已经找到最短路径的节点
        done[u] = true;
        for(int i = head[u];i != -1;i = nex[i]){
    
            //检查u的所有邻居
            int v = e[i];
            if(f[i] >= x)                               //流量约束:只走流大于x的边
                if(dist[v] > d + w[i]) {
    
    
                    dist[v] = d + w[i];
                    q.push({
    
    dist[v],v});
                }
        }
    }
    if(dist[n] != 0x3f3f3f3f) return dist[n];           //返回最短路径
    return -1;
}
int main(){
    
    
    cin>>n>>m;
    memset(head, -1, sizeof head);
    for(int i = 0;i < m;i ++) {
    
    
        int u, v, w, f;  cin>>u>>v>>w>>f;
        add(u, v, w, f);                                //存边
        add(v, u, w, f);
        flow[i] = f;                                    //把所有的流存在一个数组里
    }
    LL best_f = 0, best_w = 1, cur_w, cur_f;
    for (int i = 0;i < m ;i ++) {
    
    
        cur_f = flow[i];
        cur_w = dijkstra(flow[i]);                    //图上只保留流大于flow[i]的边,然后找最短路径
        if (cur_w != -1)
            if (cur_f* best_w > best_f * cur_w){
    
          //更新最大比
                best_f = cur_f; best_w = cur_w;
            }
    }
    cout << best_f * 1000000LL / best_w << endl;
    return 0;
}

Java代码

import java.util.*;
import java.lang.*;
import java.io.*;
class Main {
    
    
    static final int N = 1010;
    static int[] head = new int[N];
    static int[] e = new int[N*2];
    static int[] nex = new int[N*2];
    static int[] w = new int[N*2];
    static int[] f = new int[N*2];
    static int[] flow = new int[N];
    static int[] dist = new int[N];
    static boolean[] done = new boolean[N];
    static int cnt;
    static int n;
    static void add(int a, int b, int c, int d) {
    
    
        e[cnt] = b;        w[cnt] = c;
        f[cnt] = d;        nex[cnt] = head[a];
        head[a] = cnt++;
    }
    static int dijkstra(int x) {
    
    
        Arrays.fill(dist, 0x3f3f3f3f);
        Arrays.fill(done, false);
        dist[1] = 0;
        PriorityQueue<PII> q = new PriorityQueue<>(new Comparator<PII>() {
    
    
            @Override
            public int compare(PII o1, PII o2) {
    
    
                return o1.x - o2.x;
            }
        });
        q.offer(new PII(0, 1));
        while (!q.isEmpty()) {
    
    
            PII t = q.poll();
            int d = t.x;
            int u = t.y;
            if (done[u]) continue;
            done[u] = true;
            for (int i = head[u]; i != -1; i = nex[i]) {
    
    
                int v = e[i];
                if (f[i] >= x)
                    if (dist[v] > d + w[i]) {
    
    
                        dist[v] = d + w[i];
                        q.offer(new PII(dist[v], v));
                    }
            }
        }
        if (dist[n] != 0x3f3f3f3f) return dist[n];
        return -1;
    }
    public static void main(String[] args) throws Exception {
    
    
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        int m = sc.nextInt();
        Arrays.fill(head, -1);
        for (int i = 0; i < m; i++) {
    
    
            int u = sc.nextInt();
            int v = sc.nextInt();
            int c = sc.nextInt();
            int d = sc.nextInt();
            add(u, v, c, d);
            add(v, u, c, d);
            flow[i] = d;
        }
        long best_f = 0, best_w = 1, cur_w, cur_f;
        for (int i = 0; i < m; i++) {
    
    
            cur_f = flow[i];
            cur_w = dijkstra(flow[i]);
            if (cur_w != -1)
                if (cur_f * best_w > best_f * cur_w) {
    
    
                    best_f = cur_f;
                    best_w = cur_w;
                }
        }
        System.out.println(best_f * 1000000L / best_w);
    }
    static class PII {
    
    
        int x, y;
        public PII(int x, int y) {
    
    
            this.x = x;
            this.y = y;
        }
    }
}

Python代码

import heapq
N = 1010
head = [-1] * N
e = [0] * (N * 2)
nex = [0] * (N * 2)
w = [0] * (N * 2)
f = [0] * (N * 2)
flow = [0] * N
dist = [0x3f3f3f3f] * N
done = [False] * N
cnt = 0
n = 0
def add(a, b, c, d):
    global cnt
    e[cnt] = b
    w[cnt] = c
    f[cnt] = d
    nex[cnt] = head[a]
    head[a] = cnt
    cnt += 1 
def dijkstra(x):
    global dist, done, n
    dist = [0x3f3f3f3f] * N
    done = [False] * N
    dist[1] = 0
    q = []
    heapq.heappush(q, (0, 1))
    while q:
        t = heapq.heappop(q)
        d = t[0]
        u = t[1]
        if done[u]: continue
        done[u] = True
        i = head[u]
        while i != -1:
            v = e[i]
            if f[i] >= x:
                if dist[v] > d + w[i]:
                    dist[v] = d + w[i]
                    heapq.heappush(q, (dist[v], v))
            i = nex[i]
    if dist[n] != 0x3f3f3f3f:  return dist[n]
    return -1 
if __name__ == '__main__':
    n, m = map(int, input().split())
    for i in range(m):
        u, v, c, d = map(int, input().split())
        add(u, v, c, d)
        add(v, u, c, d)
        flow[i] = d
    best_f = 0
    best_w = 1
    cur_w = 0
    cur_f = 0
    for i in range(m):
        cur_f = flow[i]
        cur_w = dijkstra(flow[i])
        if cur_w != -1:
            if cur_f * best_w > best_f * cur_w:
                best_f = cur_f
                best_w = cur_w
    print(best_f * 1000000 // best_w)

猜你喜欢

转载自blog.csdn.net/weixin_43914593/article/details/131839328