Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 7037 | Accepted: 2929 |
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.
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 ai, bi, wi(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 100000100301
网络流好久没有1A了,O(∩_∩)O~~
题意:有N个整数区间,每个区间都有一个权值。现在让你从中选取一些区间,使得任意整数点的重叠数不大于M,并且这些区间的总权值最大。
思路:先离散化坐标区间,再根据得到的坐标区间建好图,下面就是MCMF了。离散化区间就不说了,直接说建图。
离散化后得到若干个坐标点和若干个区间。
建图如下:设置超级源点source,超级汇点sink
1,source向第一个坐标点建边,容量为M,费用为0;
2,对于题目给定的区间[x, y]以及该区间对应的权值z,x对应坐标点向y对应坐标点建边,容量为1,费用为z;
3,离散化后相邻区间建边,容量为M,费用为0;
4,最后一个坐标点向sink建边,容量为M,费用为0。
最后source向sink跑一次MCMF就可以了。
AC代码:
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> #define MAXN 1000 #define MAXM 10000 #define INF 0x3f3f3f3f using namespace std; struct Edge { int from, to, cap, flow, cost, next; }; Edge edge[MAXM]; int head[MAXN], edgenum; int pre[MAXN], dist[MAXN]; bool vis[MAXN]; int N, M; void init() { edgenum = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v, int w, int c) { Edge E1 = {u, v, w, 0, c, head[u]}; edge[edgenum] = E1; head[u] = edgenum++; Edge E2 = {v, u, 0, 0, -c, head[v]}; edge[edgenum] = E2; head[v] = edgenum++; } int rec[MAXN]; int Find(int val, int a, int b) { int l = a, r = b, mid; while(r >= l) { mid = (l + r) >> 1; if(rec[mid] == val) return mid; else if(rec[mid] > val) r = mid - 1; else l = mid + 1; } return -1; } int x[MAXN], y[MAXN], z[MAXN]; int source, sink; void getMap() { //坐标区间离散化 int len = 1; for(int i = 1; i <= N; i++) { scanf("%d%d%d", &x[i], &y[i], &z[i]); rec[len++] = x[i]; rec[len++] = y[i]; } sort(rec+1, rec+len); int R = 2; for(int i = 2; i < len; i++)//去重 { if(rec[i] != rec[i-1]) rec[R++] = rec[i]; } sort(rec+1, rec+R);//排序 //建图 source = 0, sink = R; for(int i = 1; i <= N; i++)//原区间建图 { int u = Find(x[i], 1, R-1);//查找所属的坐标点 int v = Find(y[i], 1, R-1); addEdge(u, v, 1, z[i]);//建边 } for(int i = 1; i < R-1; i++)//新区间 相邻的建边 addEdge(i, i+1, M, 0); addEdge(source, 1, M, 0);//源点流出 addEdge(R-1, sink, M, 0);//流入汇点 } bool SPFA(int s, int t) { queue<int> Q; memset(dist, -INF, sizeof(dist)); memset(vis, false, sizeof(vis)); memset(pre, -1, sizeof(pre)); dist[s] = 0; vis[s] = true; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = edge[i].next) { Edge E = edge[i]; if(dist[E.to] < dist[u] + E.cost && E.cap > E.flow) { dist[E.to] = dist[u] + E.cost; pre[E.to] = i; if(!vis[E.to]) { vis[E.to] = true; Q.push(E.to); } } } } return pre[t] != -1; } void MCMF(int s, int t, int &cost, int &flow) { flow = cost = 0; while(SPFA(s, t)) { int Min = INF; for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { Edge E = edge[i]; Min = min(Min, E.cap - E.flow); } for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d%d", &N, &M); init(); getMap(); int cost, flow; MCMF(source, sink, cost, flow); printf("%d\n", cost); } return 0; }