Intervals
Description You are given N weighted open intervals. The ith interval covers (ai, bi) 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. 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
POJ Founder Monthly Contest – 2008.07.27, windy7926778
|
題意是給你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;
}