HDU 6437 Videos (最小费用最大流)

题目链接

将每场电影拆成两个点,从入点向出点连边,费用是h,容量为1。从源点向它的入点、它的出点向汇点连边,费用为0,容量为1。

考虑到m很小,可以O(m^2)地在电影之间连边。如果i的结束时间不晚于j的开始时间,那么就从i的出点带j的入点连边,容量为1,若i和j为同类费用为w,否则费用为0。

最后将源点也拆成两个点,从入点到出点连边,容量为k,费用为0,表示一共只有k个人。

这样就是一个最大费用最大流的问题。存边的时候费用取负值然后跑最小费用最大流即可。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 20050;
const int INF = 0x3f3f3f3f;
const ll mod = 10000000007;

int T, n, m, k, w, no, s, t, st, ans;
int head[maxn], dis[maxn], pre[maxn];
bool vis[maxn];
struct point
{
    int l, r;
    int f, id;
}p[maxn];
struct node
{
    int to, nxt;
    int cap, flow, cost;
}e[maxn];

void add(int a, int b, int w, int x)
{
    e[no].to = b, e[no].nxt = head[a];
    e[no].cost = w, e[no].cap = x, e[no].flow = 0;
    head[a] = no++;
    e[no].to = a, e[no].nxt = head[b];
    e[no].cost = -w, e[no].cap = 0, e[no].flow = 0;
    head[b] = no++;
}

bool spfa(int s, int t)
{
    queue<int>q;
    for(int i = 0;i <= t;i++)
        dis[i] = INF, vis[i] = 0, pre[i] = -1;
    dis[s] = 0, vis[s] = 1;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u];i != -1;i = e[i].nxt)
        {
            int v = e[i].to;
            if(e[i].cap > e[i].flow && dis[v] > dis[u] + e[i].cost)
            {
                dis[v] = dis[u] + e[i].cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return (pre[t] != -1);
}

int MinCostMaxFlow(int s, int t, int &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s, t))
    {
        int minn = INF;
        for(int i = pre[t];i != -1;i = pre[e[i^1].to])
        {
            if(minn > e[i].cap - e[i].flow)
                minn = e[i].cap - e[i].flow;
        }
        for(int i = pre[t];i != -1;i = pre[e[i^1].to])
        {
            e[i].flow += minn;
            e[i^1].flow -= minn;
            cost += e[i].cost*minn;
        }
        flow += minn;
    }
    return flow;
}

int main()
{
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d%d%d", &n, &m, &k, &w);
        no = 0;
        memset(head, -1, sizeof(head));
        s = 0, t = m*2 + 2, st = m*2 + 1;
        for(int i = 1;i <= m;i++)
        {
            scanf("%d%d%d%d", &p[i].l, &p[i].r, &p[i].f, &p[i].id);
            add(i, i + m, -p[i].f, 1);
            add(i + m, t, 0, 1);
            add(st, i, 0, 1);
        }
        add(s, st, 0, k);
        for(int i = 1;i <= m;i++)
        {
            for(int j = 1;j <= m;j++)
            {
                if(i == j) continue;
                if(p[i].r <= p[j].l)
                {
                    if(p[i].id == p[j].id) add(i + m, j, w, 1);
                    else add(i + m, j, 0, 1);
                }
            }
        }
        ans = 0;
        int res = MinCostMaxFlow(s, t, ans);
        printf("%d\n", -ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/82694225