【杂题总汇】HDU多校赛第十场 Videos

【HDU2018多校赛第十场】Videos

最后一场比赛也结束了……

+HDU传送门+


◇ 题目

<简要翻译>

有n个人以及m部电影,每个人都有一个快乐值。每场电影都有它的开始、结束时间和看了这部电影会得到的快乐值。电影分成两种类型,若同一个人连续(不是时间连续,是顺序连续)看了两部相同类型的电影,他的快乐值会扣除W,数据保证扣除的值不超过电影增加的快乐值。

特别的,一个人换电影不花费时间,即若第一部电影的结束时间等于下一部电影的开始时间,是可以两场都看的;看电影必须看完;一部电影只能一个人看。

<输入&输出>

输入包含多组数据,第一行为整数T表示数据组数。

每组数据第一行包含四个整数t,m,n,W,t表示电影结束的最晚时间不超过t,m表示电影的数量,n表示人的数量,W表示连续看相同类型的电影扣除的快乐值;接下来m行,每行描述一个电影,包含四个整数——s[i]、e[i]表示第i部电影的开始和结束时间,w[i]表示看第i部电影得到的快乐值,k[i]表示电影的类型,为0或1。

输出所有人的快乐值之和的最大值。

<样例&解释>

Input Output Explain

2
10 3 1 10
1 5 1000 0
5 10 1000 1
3 9 10 0
10 3 1 10
1 5 1000 0
5 10 1000 0
3 9 10 0


2000

1990


第一组数据只有一个人,依次看了

第1,2部电影;

第二组数据只有一个人,依次看了

第1,2部电影,但类型相同,扣除

10;


◇ 解析

这道题是一道网络流的题……其中网络流的部分是队友不知道哪里找来的版,就不解释了QwQ

由于网络流的最大流无法处理多个人的情况,我们使用费用流,那么思路就非常清晰了——网络流中“流”的是人的个数,而费用就是每部电影的快乐值;

也就是说我们要求一个最大费用费用流,其实可以将所有边的费用取相反数,然后跑最小费用就可以了??

唯一难的就是建图。下面就直接列出建图方法了:

① 总共有n个人,为了避免一个人同时看了两部电影,我们先建立n个点每个点表示一个人,连接超级源点,容量为1(一个人),费用为0;

② 总共m部电影,一个人可以从任何一个电影开始看,所以建立m个节点,将每一部电影都跟所有的人连接,容量为1,费用为电影的快乐值(走过这条边就会增加快乐值,相当于看了这部电影,且限制了看电影的人数);

③ 若第i部电影的结束时间小于等于第j部电影的结束时间,则在第i部电影和第j部电影之间连边,容量依然为1,费用为第j部电影的快乐值,若电影i,j的类型相同,边的费用减去W(看完第i部电影再看第j部);

④ 由于一个人可以看完一部电影就不看了,即可以从任何一部电影结束,所以将所有电影与超级汇点连边;没有必要在人与汇点连边,因为看一部电影始终优于不看,则限制每个人都要看电影。

但是交上去就WA了,后面一个dalao来检查了一下~发现了一个BUG:

虽然有边的容量限制人数,但是下面这种情况会出现两个人看了同一部电影:

如何解决这种问题?

根据以前做题的经验(好吧,其实是dalao直接告诉我们的)我们需要拆点——将每一个电影节点拆分出一个虚拟节点,真节点与虚拟节点之间连一条容量为1,花费为0的边,所有以电影i为末尾的边都连在真节点上,而以电影i出发的边都连在虚拟节点上——只要经过电影i,则必然要通过真节点和虚拟节点的边,这样就限制了一个人通过。

虽然话是这么说,但是实际上建边时,边的花费我都取了相反数,这样就能够用跑最小费用流代替最大费用流,有负权边,注意选择合适的方法。


◇ 源代码(其中最小费用流的部分是从不知道哪个dalao那里copy过来的……真是非常感谢!!)

/*Lucky_Glass*/
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
/*以下均是模板*/
const int N = 50002;
const int M = 500005;
#define INF 0x3f3f3f3f
struct E
{
    int to,cap,cost,flow,next;
}e[2*M];int head[N] , ecnt;
int  pre[N];
int dis[N];
bool vis[N];
int n,m,S,T;

void Clear()
{
    ecnt = 0;
    memset(head,-1,sizeof head);
}

void adde(int fr,int to,int cap,int cost)
{
    e[ecnt]=(E){to,cap,-cost,0,head[fr]};
    head[fr] = ecnt++;
    e[ecnt]=(E){fr,0,cost,0,head[to]};
    head[to] = ecnt++;
}

bool SPFA(int s,int t)
{
    memset(vis,0,sizeof vis);
    memset(dis,0x3f,sizeof dis);
    memset(pre,-1,sizeof pre);
    queue <int> q;
    q.push(s);dis[s] = 0;vis[s]=1;

    while (!q.empty())
    {
        int cur = q.front();q.pop();vis[cur] = false;
        for (int j=head[cur];j!=-1;j=e[j].next)
        {
            int to = e[j].to;
            if (dis[to] > dis[cur] + e[j].cost && e[j].cap > e[j].flow )
            {
                dis[to] = dis[cur] + e[j].cost;
                pre[to] = j;
                if (!vis[to])
                {
                    q.push(to);
                    vis[to] = true;
                }
            }
        }
    }
    return pre[t] != -1;
}

void MCMF (int s,int t,int &maxflow,int &mincost)
{
    maxflow = mincost = 0;
    while (SPFA(s,t))
    {
        int MIN = INF;
        for (int j=pre[t]; j!=-1;j=pre[e[j^1].to])
        {
            MIN = min(MIN,e[j].cap - e[j].flow);
        }
        for (int j=pre[t]; j!=-1;j=pre[e[j^1].to])
        {
            e[j].flow += MIN;
            e[j^1].flow -= MIN;
            mincost += MIN * e[j].cost;
        }
        maxflow += MIN;
    }
}
/*模板结束*/
#define MAXN 3000

int L[MAXN+5],R[MAXN+5],Lk[MAXN+5],Kd[MAXN+5];
int main(){
    int TT;
    cin>>TT;//数据组数
    while(TT--){
        Clear();//清空
        int nn,mm,kk,ht;
        cin>>nn>>mm>>kk>>ht;
        for(int i=1;i<=mm;i++)
            cin>>L[i]>>R[i]>>Lk[i]>>Kd[i];
        S=1,T=kk+mm*2+2;
//超级源点为1,超级汇点为最后一个点(因为有kk个人节点,mm*2个电影节点,即真节点和虚拟节点,再加上一个源点)
        for(int i=1;i<=kk;i++)
            adde(S,i+1,1,0); //在人节点和源点之间连边,第i个人编号为i+1
        for(int i=1;i<=kk;i++)
            for(int j=1;j<=mm;j++)
                adde(i+1,j+kk+1,1,Lk[j]); //在人和电影的真节点之间连边,第i部电影真节点编号为i+kk+1
        for(int i=1;i<=mm;i++)
            adde(i+kk+1,i+kk+mm+1,1,0); //连接真节点和虚拟节点,第i部电影的虚拟节点编号为i+kk+mm+1
        for(int i=1;i<=mm;i++)
            adde(i+kk+mm+1,T,1,0); //连接虚拟节点和汇点
        for(int i=1;i<=mm;i++)
            for(int j=1;j<=mm;j++)
                if(i!=j&&R[i]<=L[j]){ //电影之间连边,虚拟节点连真节点
                    if(Kd[i]!=Kd[j])
                        adde(i+kk+mm+1,j+kk+1,1,Lk[j]);
                    else
                        adde(i+kk+mm+1,j+kk+1,1,Lk[j]-ht);
                }
        int ans1,ans2;
        MCMF(S,T,ans1,ans2);
        cout<<-ans2<<"\n"; //由于边权取了相反数,输出答案时也需要取相反数
    }
}

  


The End

Thanks for reading!

- Lucky_Glass

(Tab:如果我有没讲清楚的地方可以直接在邮箱[email protected] email我,在周末我会尽量解答并完善博客~??)

原文地址:https://www.cnblogs.com/LuckyGlass-blog/p/9519886.html

时间: 2024-10-09 12:34:54

【杂题总汇】HDU多校赛第十场 Videos的相关文章

HDU多校赛第9场 HDU 4965Fast Matrix Calculation【矩阵运算+数学小知识】

难度上,,,确实,,,不算难 问题是有个矩阵运算的优化 题目是说给个N*K的矩阵A给个K*N的矩阵B(1<=N<=1000 && 1=<K<=6),先把他们乘起来乘为C矩阵,然后算C^(N*N) 相当于 ABABABABABABAB...=(AB)^(N*N) 不如 A(BA)^(N*N-1)B 因为BA乘得K*K的矩阵,K是比较小的 #include <cstdio> #include <cstdlib> #include <cstr

hdu 4970 Killing Monsters(简单题) 2014多校训练第9场

Killing Monsters                                                                        Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description Kingdom Rush is a popular TD game, in which you should b

【多校赛第三场】Redraw Beautiful Drawings【网络流】【谜のWA】

参考题解:http://blog.csdn.net/qian99/article/details/38276887 #include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <queue> #include <vector> #include <algorithm>

【杂题总汇】HDU-5215 Cycle

◆HDU-5215◆ Cycle 国庆节集训的第三天……讲图论,心情愉快……刷了一堆水题,不过也刷了一些有意思的题 +传送门+ HDU ? 题目 给出一个无向图(无自环,无重边),求该无向图中是否存在奇环.偶环. 多组数据,每组数据第一行为n,m表示点和边的数量,接下来m行每行描述一条边. 对于每组数据,输出两行,第一行输出是否存在奇环,第二行输出是否存在偶环. ? 解析 因为是一个简单图,这道题就简单了很多. (1)判断奇环 有一类图是不包含奇数环的——二分图,反过来也是这样——二分图是不包含

郑州大学2018新生训练赛第十场题解

比赛(补题)地址:http://222.22.65.164/problemset.php 题号为:4305 -- 4309 总述:这次新生赛难度偏于平和,但涵盖方面甚广,其中一道签到题是c语言题,并且有两道是hdu一百题的原题,一道简单的最小生成树,唯一"有些难度"的应该是一道数论题(毕竟本来自己就是搞数学的).   A.沙漠骆驼 这是一道经典的递推问题,原型为HDU 2044的"一只小蜜蜂-".思路很简单,以第5个沙丘为例,到达第五个沙丘的方式有两种:从第3个向

hdu 2015校赛1002 Dual horsetail (思维题 )

Dual horsetail Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 500    Accepted Submission(s): 189 Problem Description Nanaya's favorite Dual horsetail robot has run out of power!  As a best frie

2015 多校赛 第五场 1010 (hdu 5352)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352 看题看得心好累. 题目大意: 给出 n 个点,依次执行 m 次操作:输入“1 x”时,表示将与 x 连通的点全部修复:输入“2 x y”,表示在 x 与 y 之间加一条边:输入“3 x y”,表示删除 x 与 y 之间的边.题目确保不会与重边并且操作合法. 题目会给出 k,要求每次修复的的点的数目小于等于k. 问:怎样执行操作1,使得令修复点数最多的同时,令每次执行操作1所修复的点的数目所构成

2015 多校赛 第四场 1009 (hdu 5335)

Problem Description In an n∗m maze, the right-bottom corner is the exit (position (n,m) is the exit). In every position of this maze, there is either a 0 or a 1 written on it. An explorer gets lost in this grid. His position now is (1,1), and he want

hdu 5328 Problem Killer(杭电多校赛第四场)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5328 题目大意:找到连续的最长的等差数列or等比数列. 解题思路:1.等差等比的性质有很多.其中比较重要的一个就是解题关键:如a[i-2],a[i-1],a[i],a[i+1]这个序列.a[i-2],a[i-1],a[i]是等差数列,a[i-1],a[i],a[i+1]也是等差数列.那么a[i-2],a[i-1],a[i],a[i+1]就是等差数列.  2. 等比数列也是一样的~~只要根据这个性质就