标签:
题意最后可以简化为
给出若干个区间,每个区间由左端点,右端点, 权值构成。
挑出若干个区间,使得权值和最大,但必须满足区间任意部分重叠次数不超过k
这题跟POJ3680一样一样的
构图是这样
先把这些区间都给hash了。
hash完必然这些区间端点都落在1,2,3..., cnt 这些数中, cnt是hash完 不同数的个数
然后建边, 源点为S,汇点为T
S到1 建边 流量为k 费用为0
1到2,2到3,3到4....cnt-1到cnt 分别建边 流量为k 费用为0
cnt到T建边 流量为k 费用为0
然后对于每个区间[l,r] 费用为w的
建边 l 到 r 流量为1 费用为-w
这样你在图上一画
就能知道这样做的巧妙的。
那样互相之间不会重叠的区间, 一个流量就可以把他们都走完。
重叠了的区间自然要受到k这个限制。
每个区间走掉1个流量之后,会在右端点回归大部队
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 4005
#define MAXM 1122222
#define INF 1000000001
using namespace std;
struct Interval {
int a, b, w;
}p[2222];
int a[5555];
int nt, k;
int getnum(char a, char b) {
return (a - '0') * 10 + (b - '0');
}
int gethash(char s[]) {
int a = getnum(s[0], s[1]);
int b = getnum(s[3], s[4]);
int c = getnum(s[6], s[7]);
return a * 3600 + b * 60 + c;
}
struct EDGE
{
int v, cap, cost, next, re; // re记录逆边的下标。
} edge[MAXM];
int n, m, ans, flow, src, des;
int e, head[MAXN];
int que[MAXN], pre[MAXN], dis[MAXN];
bool vis[MAXN];
void init()
{
e = ans = flow = 0;
memset(head, -1, sizeof(head));
}
void add(int u, int v, int cap, int cost)
{
edge[e].v = v;
edge[e].cap = cap;
edge[e].cost = cost;
edge[e].next = head[u];
edge[e].re = e + 1;
head[u] = e++;
edge[e].v = u;
edge[e].cap = 0;
edge[e].cost = -cost;
edge[e].next = head[v];
edge[e].re = e - 1;
head[v] = e++;
}
bool spfa()
{
int i, h = 0, t = 1;
for(i = 0; i <= n; i ++)
{
dis[i] = INF;
vis[i] = false;
}
dis[src] = 0;
que[0] = src;
vis[src] = true;
while(t != h)
{
int u = que[h++];
h %= n;
vis[u] = false;
for(i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(edge[i].cap && dis[v] > dis[u] + edge[i].cost)
{
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v])
{
vis[v] = true;
que[t++] = v;
t %= n;
}
}
}
}
if(dis[des] == INF) return false;
return true;
}
void end()
{
int u, p, mi = INF;
for(u = des; u != src; u = edge[edge[p].re].v)
{
p = pre[u];
mi = min(mi, edge[p].cap);
}
for(u = des; u != src; u = edge[edge[p].re].v)
{
p = pre[u];
edge[p].cap -= mi;
edge[edge[p].re].cap += mi;
ans += mi * edge[p].cost; // cost记录的为单位流量费用,必须得乘以流量。
}
flow += mi;
}
int main() {
while(scanf("%d%d", &nt, &k) != EOF) {
char s[11];
int w;
int cnt = 0;
for(int i = 0; i < nt; i++) {
scanf("%s", s);
p[i].a = gethash(s);
scanf("%s", s);
p[i].b = gethash(s);
scanf("%d", &w);
p[i].w = w;
a[cnt++] = p[i].a;
a[cnt++] = p[i].b;
}
sort(a, a + cnt);
cnt = unique(a, a + cnt) - a;
for(int i = 0; i < nt; i++) {
p[i].a = lower_bound(a, a + cnt, p[i].a) - a + 1;
p[i].b = lower_bound(a, a + cnt, p[i].b) - a + 1;
}
init();
src = cnt + 1;
des = cnt + 2;
n = cnt + 2;
for(int i = 1; i < cnt; i++) add(i, i + 1, k, 0);
add(src, 1, k, 0);
add(cnt, des, k, 0);
for(int i = 0; i < nt; i++) {
add(p[i].a, p[i].b, 1, -p[i].w);
}
while(spfa() && dis[des] < 0) end();
printf("%d\n", -ans);
}
return 0;
}
POJ 3762 The Bonus Salary! 最小费用最大流
标签:
原文地址:http://blog.csdn.net/sdj222555/article/details/43057353