hdu 6437 Videos 最小费用最大流裸题 模板

Problem L.Videos

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0

 

Problem Description

C-bacteria takes charge of two kinds of videos: ’The Collection of Silly Games’ and ’The Collection of Horrible Games’.
For simplicity’s sake, they will be called as videoA and videoB.
There are some people who want to watch videos during today, and they will be happy after watching videos of C-bacteria.
There are n hours a day, m videos are going to be show, and the number of people is K.
Every video has a type(videoA or videoB), a running time, and the degree of happi- ness after someone watching whole of it.
People can watch videos continuous(If one video is running on 2pm to 3pm and another is 3pm to 5pm, people can watch both of them).
But each video only allows one person for watching.
For a single person, it’s better to watch two kinds to videos alternately, or he will lose W happiness.
For example, if the order of video is ’videoA, videoB, videoA, videoB, …’ or ’B, A, B, A, B, …’, he won’t lose happiness; But if the order of video is ’A, B, B, B, A, B, A, A’, he will lose 3W happiness.
Now you have to help people to maximization the sum of the degree of happiness.

 

 

Input

Multiple query.
On the first line, there is a positive integer T, which describe the number of data. Next there are T groups of data.
for each group, the first line have four positive integers n, m, K, W : n hours a day, m videos, K people, lose W happiness when watching same videos).
and then, the next m line will describe m videos, four positive integers each line S, T, w, op : video is the begin at S and end at T, the happiness that people can get is w, and op describe it’s tpye(op=0 for videoA and op=1 for videoB).
There is a blank line before each groups of data.
T<=20, n<=200, m<=200, K<=200, W<=20, 1<=S<T<=n, W<=w<=1000,
op=0 or op=1

 

 

Output

Your output should include T lines, for each line, output the maximum happiness for the corresponding datum.

 

 

Sample Input

 

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

 

 

Sample Output

 

2000

1990


题意:

    一天中有n个小时,有m部电影,有k个人要看电影,还有一个M(后面解释)。对于每一部电影,都会有4个属性值,开始时间S,结束时间T,看完电影的开心值w,和它的类型(A或者B)。一个人同时只能看一部电影,看完一部电影之后可以看其他开始时间大于等于该部电影结束时间的电影(即如果先看了1-5的电影 接下来可以看5-6或者6-8的电影,但是不能看4-9的电影)。如果你再一次看了类型相同的电影,你会失去M点开心值(即如果你看了AAB,你会在A->A上失去M点开心值)。问你能得到的最大开心值是多少。

 

做法:

     最小费用流裸题的样子,我的做法好像有点麻烦,我给K个人K个点(范围是1-200)。从超级源点(0)向他们连了流量为1的边,每个人向每个电影开始的结点连边,每个电影之间连边(我给每个电影200个点,表示第i部电影在第j个小时时候的点)权值为负的开心值,然后在可以连续看的电影之间连边(先看的尾巴->后看的头 如果类型相同费用就是0 不同费用就是W 是正的所以最后计算的时候会减掉)。然后丢进板子跑一遍就好啦。

 


代码如下:

  

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=400000;
const int maxm=1000000;
const int inf=0x3f3f3f3f;
int dis[maxn];
int vis[maxn],pre[maxn];
int head[maxn],cnt,viss[maxn],visss[maxm];
int n,m,sp,tp,k,W;
ll ans=0;
struct node{
    int to,cap,cost,next;
}e[maxm];
void add(int from,int to,int cap,int cost){
    e[cnt].to=to; e[cnt].cap=cap;
    e[cnt].cost=cost; e[cnt].next=head[from];
    head[from]=cnt++;

    e[cnt].to=from; e[cnt].cap=0;
    e[cnt].cost=-cost; e[cnt].next=head[to];
    head[to]=cnt++;
}
bool spfa(int s,int t,int &flow,int &cost){
    queue<int> q;
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s]=0;  q.push(s);
    vis[s]=1;
    int d=inf;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];~i;i=e[i].next){
            int v=e[i].to;
            if(e[i].cap>0&&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);
                }
            }
        }
    }
    if(dis[t]==inf){
        return false;
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        d=min(d,e[i].cap);
    }
    for(int i=pre[t];~i;i=pre[e[i^1].to]){
        e[i].cap-=d;
        e[i^1].cap+=d;
        cost+=e[i].cost*d;
    }
    flow+=d;
    return true;
}
int mcmf(int s,int t){
    int flow=0,cost=0;
    while(spfa(s,t,flow,cost)){
        //cout<<flow<<" "<<cost<<endl;
    }
    return cost;
}
int gainp(int m,int n){
    return 200+(m-1)*200+n;
}
struct vid{
    int st,en,val,ty,id;
    bool operator <(const vid &a) const {
        return en<a.en;
    }
}vs[205];
vector<vid> vide[201];
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(visss,0,sizeof(visss));
        memset(viss,0,sizeof(viss));
        memset(head,-1,sizeof(head));
        ans=0;
        scanf("%d%d%d%d",&n,&m,&k,&W);
        for(int i=1;i<=n;i++){
            vide[i].clear();
        }
        sp=0;tp=50001;
        for(int i=1;i<=k;i++){
            add(sp,i,1,0);
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%d",&vs[i].st,&vs[i].en,&vs[i].val,&vs[i].ty);
            vs[i].id=i;
            vide[vs[i].st].push_back(vs[i]);
        }
        for(int i=1;i<=k;i++){
            for(int j=1;j<=m;j++){
                add(i,gainp(j,vs[j].st),1,0);
            }
        }
        for(int i=1;i<=m;i++){
            int now=vs[i].en;
            for(int j=now;j<=n;j++){
                for(int k=0;k<vide[j].size();k++){
                    vid x=vide[j][k];
                    if(x.ty==vs[i].ty){
                        add(gainp(i,vs[i].en),gainp(x.id,x.st),1,W);
                    }
                    else {
                        add(gainp(i,vs[i].en),gainp(x.id,x.st),1,0);
                    }
                }
            }
            add(gainp(i,vs[i].st),gainp(i,vs[i].en),1,-vs[i].val);
            if(vs[i].en!=n) add(gainp(i,vs[i].en),gainp(i,n),1,0);
            add(gainp(i,n),tp,1,0);
        }
        cout<<-mcmf(sp,tp)<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值