zoukankan      html  css  js  c++  java
  • POJ 3680:Intervals(最小费用最大流)***

    http://poj.org/problem?id=3680

    题意:给出n个区间[Li,Ri],每个区间有一个权值wi,要使得每个点都不被超过k个区间覆盖(最多能被k个区间覆盖),如果选取了第i个区间,那么能得到wi的权值,问最终能得到的最大权值是多少。

    思路:首先把区间离散化,然后考虑构图。

    第一种构图方式:

    将S到第一个区间结点连一条容量为k,费用为0的边,代表最多能使用k个区间。

    对于每个区间[l,r],从l到r连一条容量为1,费用为-w[i]的边(因为跑的是最大的费用),这里如果这条边的流量为1,那么代表使用了这个区间,那么就加上费用。

    将最后一个区间结点连一条容量为k,费用为0的边,同S。

    对于每个离散化后的区间,将i和i+1连一条容量为INF,费用为0的边,如果不跑这条边,那么说明这段区间被覆盖了。

    最后将答案取反就是最终答案。

    画了个图帮助理解:如果跑1->3的区间的话,那么1->3的流量是1,那么主路径在[1,3]的时候流量为k-1,然后跑2->4,主路径在[2,3]的流量就变成k-2,跑到3的时候就变回k-1,跑到4又变回k,如果k=0的时候,那么就不能被覆盖了,因此恰好可以满足限制。

    第二种构图方式:

    是挑战上的,对于有负权边的构图。

    S和T和i到i+1的连边和上图一样。

    对于[u,v],S到v连一条容量为1,费用为0的边,u到T连一条容量为1,费用为0的边,v到u连一条容量为1,费用为wi的边。

    这个方法还不太理解。

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <iostream>
      4 #include <cstring>
      5 #include <string>
      6 #include <cmath>
      7 #include <queue>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <stack>
     12 using namespace std;
     13 #define INF 0x3f3f3f3f
     14 #define N 510
     15 typedef long long LL;
     16 struct Edge {
     17     int u, v, nxt, cap, cost;
     18 } edge[N*N];
     19 int head[N], tot, pre[N], dis[N], vis[N], a[N], b[N], w[N], S, T;
     20 vector<int> vec;
     21 
     22 void Add(int u, int v, int cap, int cost) {
     23     edge[tot] = (Edge) { u, v, head[u], cap, cost }; head[u] = tot++;
     24     edge[tot] = (Edge) { v, u, head[v], 0, -cost }; head[v] = tot++;
     25 }
     26 
     27 bool SPFA(int S) {
     28     queue<int> que;
     29     que.push(S);
     30     memset(dis, INF, sizeof(dis));
     31     memset(vis, 0, sizeof(vis));
     32     dis[S] = 0; vis[S] = 1;
     33     while(!que.empty()) {
     34         int u = que.front(); que.pop();
     35         vis[u] = 0;
     36         for(int i = head[u]; ~i; i = edge[i].nxt) {
     37             int v = edge[i].v, cost = edge[i].cost, cap = edge[i].cap;
     38             if(dis[v] > dis[u] + cost && cap > 0) {
     39                 dis[v] = dis[u] + cost;
     40                 pre[v] = i;
     41                 if(!vis[v]) vis[v] = 1, que.push(v);
     42             }
     43         }
     44     }
     45     return dis[T] < INF;
     46 }
     47 
     48 int MFMC(int S, int T) {
     49     int ans = 0, u, flow;
     50     while(SPFA(S)) {
     51         flow = INF, u = T;
     52         while(u != S) {
     53             if(flow > edge[pre[u]].cap) flow = edge[pre[u]].cap;
     54             u = edge[pre[u]].u;
     55         } u = T;
     56         while(u != S) {
     57             edge[pre[u]].cap -= flow; edge[pre[u]^1].cap += flow;
     58             ans += flow * edge[pre[u]].cost;
     59             u = edge[pre[u]].u;
     60         }
     61     }
     62     return ans;
     63 }
     64 
     65 int main() {
     66     int n, k, t; scanf("%d", &t);
     67     while(t--) {
     68         scanf("%d%d", &n, &k);
     69         memset(head, -1, sizeof(head)); tot = 0;
     70         vec.clear();
     71         for(int i = 1; i <= n; i++)
     72             scanf("%d%d%d", &a[i], &b[i], &w[i]), vec.push_back(a[i]), vec.push_back(b[i]);
     73         sort(vec.begin(), vec.end());
     74         vec.erase(unique(vec.begin(), vec.end()), vec.end()); // 新的离散化姿势
     75         int cnt = vec.size();
     76         S = 0, T = cnt + 1;
     77         int ans = 0;
     78 
     79 //      First
     80         Add(S, 1, k, 0); Add(cnt, T, k, 0);
     81         for(int i = 1; i < cnt; i++) Add(i, i + 1, INF, 0);
     82         for(int i = 1; i <= n; i++) {
     83             int u = lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin() + 1;
     84             int v = lower_bound(vec.begin(), vec.end(), b[i]) - vec.begin() + 1;
     85             Add(u, v, 1, -w[i]);
     86         }
     87         ans -= MFMC(S, T);
     88 
     89 //        Second
     90 //        Add(S, 1, k, 0); Add(cnt, T, k, 0);
     91 //        for(int i = 1; i < cnt; i++) Add(i, i + 1, INF, 0);
     92 //        for(int i = 1; i <= n; i++) {
     93 //            int u = lower_bound(vec.begin(), vec.end(), a[i]) - vec.begin() + 1;
     94 //            int v = lower_bound(vec.begin(), vec.end(), b[i]) - vec.begin() + 1;
     95 //            Add(S, v, 1, 0); Add(u, T, 1, 0);
     96 //            Add(v, u, 1, w[i]);
     97 //            ans += w[i];
     98 //        }
     99 //        ans -= MFMC(S, T);
    100         printf("%d
    ", ans);
    101     }
    102     return 0;
    103 }
    104 
    105 /*
    106 3 1
    107 1 2 2
    108 2 3 4
    109 3 4 8
    110 3 1
    111 1 3 2
    112 2 3 4
    113 3 4 8
    114 3 2
    115 1 100000 100000
    116 1 150 301
    117 100 200 300
    118 */
  • 相关阅读:
    Kafka 消费者及消费者分区策略
    c++与c
    Exactly Once 语义
    如何在CentOS 8服务器上安装FreeIPA身份和授权解决方案?
    如何在Linux Mint 20上安装Wine
    如何在Ubuntu 20.04 LTS服务器上安装Wireguard
    如何在Ubuntu 20.04 LTS服务器上安装Apache JMeter
    如何在Linux服务器中使用SAR命令
    MongoDB是什么,它是如何工作的?
    如何在Ubuntu 20.04 LTS上安装SSH服务器
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6751750.html
Copyright © 2011-2022 走看看