POJ 2680 —— 最小費用流求解區間圖的最大權獨立集問題

Intervals
Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 5967   Accepted: 2400

Description

You are given N weighted open intervals. The ith interval covers (aibi) and weighs wi. Your task is to pick some of the intervals to maximize the total weights under the limit that no point in the real axis is covered more than k times.

Input

The first line of input is the number of test case.
The first line of each test case contains two integers, N and K (1 ≤ K ≤ N ≤ 200).
The next N line each contain three integers aibiwi(1 ≤ ai < bi ≤ 100,000, 1 ≤ wi ≤ 100,000) describing the intervals. 
There is a blank line before each test case.

Output

For each test case output the maximum total weights in a separate line.

Sample Input

4

3 1
1 2 2
2 3 4
3 4 8

3 1
1 3 2
2 3 4
3 4 8

3 1
1 100000 100000
1 2 3
100 200 300

3 2
1 100000 100000
1 150 301
100 200 300

Sample Output

14
12
100000
100301

Source

題意是給你n段區間,讓你找出任意點不超過k個區間覆蓋的總權重

思路:問題等價於把n個區間劃分爲k個互不相交區間組成的子集,最大化權值和。轉化爲找流量爲k的最小費用流問題。注意圖中有負權,我們把負權邊初始滿流然後再用Bellman-Ford求解。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
using namespace std;
///#define Online_Judge
#define outstars cout << "***********************" << endl;
#define clr(a,b) memset(a,b,sizeof(a))
#define lson l , mid  , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define mk make_pair
#define FOR(i , x , n) for(int i = (x) ; i < (n) ; i++)
#define FORR(i , x , n) for(int i = (x) ; i <= (n) ; i++)
#define REP(i , x , n) for(int i = (x) ; i > (n) ; i--)
#define REPP(i ,x , n) for(int i = (x) ; i >= (n) ; i--)
const int MAXN = 400 + 50;
const int sigma_size = 26;
const long long LLMAX = 0x7fffffffffffffffLL;
const long long LLMIN = 0x8000000000000000LL;
const int INF = 0x7fffffff;
const int IMIN = 0x80000000;
#define eps 1e-8
const int MOD = (int)1e9 + 7;
typedef long long LL;
const double PI = acos(-1.0);

typedef pair<int , int> pi;
#define Bug(s) cout << "s = " << s << endl;
///#pragma comment(linker, "/STACK:102400000,102400000")
int n , k;
int a[MAXN] , b[MAXN] , w[MAXN];
///用於表示邊的結構體(終點,容量,費用,反向邊)
struct edge{int to , cap, cost , rev;};
int V;///頂點數
vector<edge> G[MAXN];///圖的鄰接表表示
int dist[MAXN];///最短距離
int prevv[MAXN] , preve[MAXN];///最短路中的前驅節點和對應的邊
///向圖中增加一條從from到to容量爲cap費用爲cost的邊
void add_edge(int from , int to , int cap , int cost)
{
    G[from].push_back((edge){to , cap ,cost , G[to].size()});
    G[to].push_back((edge){from , 0 , -cost , G[from].size() - 1});
}
///求解從s到t流量爲f的最小費用流
///如果不能再增廣則返回-1
int min_cost_flow(int s , int t , int f)
{
    int res = 0;
    while(f > 0)
    {
        ///利用Bellman-Ford算法求s到t的最短路
        fill(dist , dist + V , INF);
        dist[s] = 0;
        bool update = true;
        while(update)
        {
            update = false;
            for(int v = 0 ; v < V ;v ++)
            {
                if(dist[v] == INF)continue;
                for(int i = 0; i < G[v].size(); i ++)
                {
                    edge &e = G[v][i];
                    if(e.cap > 0 && dist[e.to] > dist[v] + e.cost)
                    {
                        dist[e.to] = dist[v] + e.cost;
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        update = true;
                    }
                }
            }
        }
        ///不能再增廣
        if(dist[t] == INF)return -1;
        ///沿s到t的最短路儘量增廣
        int d = f;
        for(int v = t ; v != s ; v = prevv[v])
        {
            d = min(d , G[prevv[v]][preve[v]].cap);
        }
        f -= d;
        res += d * dist[t];
        for(int v = t ; v != s ; v = prevv[v])
        {
            edge &e = G[prevv[v]][preve[v]];
            e.cap -= d;
            G[v][e.rev].cap += d;
        }
    }
    return res;
}
void solve()
{
    vector<int>x;
    for(int i = 0 ; i < n ; i++)
    {
        x.push_back(a[i]);
        x.push_back(b[i]);
    }
    sort(x.begin() , x.end());
    x.erase(unique(x.begin() , x.end()) , x.end());
    int g = x.size();
    int s = g  , t = s + 1;
    V = t + 1;
    int res = 0;
    add_edge(s , 0 , k , 0);
    add_edge(g - 1 , t , k , 0);
    for(int i = 0 ; i < g - 1 ; i ++)
    {
        add_edge(i , i + 1 , INF , 0);
    }
    for(int i = 0 ; i < n ; i ++)
    {
        int u = find(x.begin() , x.end() , a[i]) - x.begin();
        int v = find(x.begin() , x.end() , b[i]) - x.begin();
        add_edge(v , u , 1 , w[i]);
        add_edge(s , v , 1 , 0);
        add_edge(u , t , 1 , 0);
        res -= w[i];
    }
    res += min_cost_flow(s , t , n + k);
    printf("%d\n" , -res);
}
int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        clr(preve , 0);
        clr(prevv , 0);
        clr(G , 0);
        scanf("%d%d" , &n , &k);
        for(int i = 0  ; i < n ; i++)
        {
            scanf("%d%d%d" , &a[i] , &b[i] , &w[i]);
        }
        solve();
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章