• [hdu6437]Problem L. Videos


    题目大意:有$n$个小时,有$m$个节目(每种节目都有类型$0/1$),有$k$个人,一个人连续看相同类型的节目会扣$w$快乐值。

    每一种节目有都一个播放区间$[l,r]$。每个人同一时间只能看一个节目,第$i$个节目只能一个人看,看完可以获得快乐$val_i$。问最多可以获得多少快乐?

    题解:最大费用最大流,为了保证每个影片只被一个人观看,将其拆为入点和出点,入点和出点之间连一条容量为$1$,花费为$0$的边。

    建一个源点$ST$和次源点$st$。从$ST$向$st$建一条容量为$k$,花费为$0$的边,表示有$k$个人可以看影片。

    从$st$点向每个入点连一条容量为$1$,花费为$val_i$的边,若两个影片的时间不相交($T_u leqslant S_v$),那么在$u$到$v$之间建一条容量为$1$,花费为$val_v$的边;若$u,v$属性相同则花费为$val_v-W$。

    最后将每个出点向汇点连一条容量为$1$,花费为$0$的边。

    卡点:1.不知道为啥数组开小(计算出来不会锅)

    ​   2.换电脑的时候代码未保存,把一份错误代码复制了过去(调了我一天)

    C++ Code:

    #include <cstdio>
    #include <cstring>
    #define maxn 1010
    #define maxm 50100
    const int inf = 0x3f3f3f3f;
    int Tim;
    int n, m, K, W, st, ed;
    struct node {
    	int S, T, w, ty;
    } s[maxn];
    int q[maxn], h, t;
    int d[maxn], pre[maxn];
    bool vis[maxn];
    int head[maxn], cnt = 2;
    struct Edge {
        int to, nxt, w, cost;
    } e[maxm << 1];
    void add(int a, int b, int c, int d) {
        e[cnt] = (Edge) {b, head[a], c, d}; head[a] = cnt;
        e[cnt ^ 1] = (Edge) {a, head[b], 0, -d}; head[b] = cnt ^ 1;
        cnt += 2;
    }
    inline int min(int a, int b) {return a < b ? a : b;}
    bool spfa() {
        for (int i = st; i <= ed; i++) d[i] = -inf;
        d[q[h = t = 0] = st] = 0;
        while (h <= t) {
            int u = q[h++];
            vis[u] = false;
            for (int i = head[u]; i; i = e[i].nxt) {
                int v = e[i].to;
                if (e[i].w && d[v] < d[u] + e[i].cost) {
                    d[v] = d[u] + e[i].cost;
                    pre[v] = i;
                    if (!vis[v]) {
                        q[++t] = v;
                        vis[v] = true;
                    }
                }
            }
        }
        return d[ed] != -inf;
    }
    int update() {
        int ans, mf = inf;
        for (int i = pre[ed]; i; i = pre[e[i ^ 1].to]) mf = min(mf, e[i].w);
        ans = mf * d[ed];
        for (int i = pre[ed]; i; i = pre[e[i ^ 1].to]) e[i].w -= mf, e[i ^ 1].w += mf;
        return ans;
    }
    void MCMF() {
        int ans = 0;
        while (spfa()) ans += update();
        printf("%d
    ", ans);
    }
    int main() {
    	scanf("%d", &Tim);
    	while (Tim --> 0) {
    	    scanf("%d%d%d%d", &n, &m, &K, &W);
    	    st = 0; ed = m + 1 << 1;
    	    add(st, 1, K, 0);
    	    for (int i = 1; i <= m; i++) {
    	        scanf("%d%d%d%d", &s[i].S, &s[i].T, &s[i].w, &s[i].ty);
    	        add(i << 1, i << 1 | 1, 1, 0);
    	        add(1, i << 1, 1, s[i].w);
    	        add(i << 1 | 1, ed, 1, 0);
    	    }
    	    for (int i = 1; i <= m; i++) {
    	    	for (int j = 1; j <= m; j++) {
    	    		if (i != j && s[i].T <= s[j].S) add(i << 1 | 1, j << 1, 1, (s[i].ty == s[j].ty) ? s[j].w : s[j].w - W);
    			}
    		}
    	    MCMF();
    	    if (Tim) memset(head, 0, sizeof head), cnt = 2;
    	}
        return 0;
    }
    

      

  • 相关阅读:
    【软件工程】学期总结
    【操作系统】实验四 主存空间的分配和回收
    学术诚信与职业道德
    【软件工程】《构建之法》八、九、十章读后感
    【操作系统】实验三 进程调度模拟程序
    【软件工程】《构建之法》6-7章读后感
    【操作系统】实验二 作业调度模拟程序
    【软件工程】复利计算器--结对编程3.0评论博客
    复利计算器--结对编程2.0
    学习进度条
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9677449.html
Copyright © 2020-2023  润新知