HDU6437 Videos (2018多校第十场1012) (网络流-最小费用最大流)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jerry99s/article/details/81977832

题目:
http://acm.hdu.edu.cn/showproblem.php?pid=6437

题意:
一天n小时,m个电影,k个人(可以有人不去看电影);
电影i放映时间在第si~ti小时,电影有个属性(A or B);
电影i有快乐值wi;
连续看同一属性的电影会产生不快乐值W;
求所有人的快乐值之和最大;

分析:
注意到一个结论:越多人看电影越好,把人数当流量,就可以求最大流下的最小费用;
由于m很小,所以可以O(m^2)地处理出各电影间的连边;
若y电影在x电影之后放映,且不同类,则从x到y连一条流量为1,费用为wy的边;
若y电影在x电影之后放映,且同类,则从x到y连一条流量为1,费用为wy-W的边;
然后建立一个起点,分别连到各个电影点一条流量为1,费用为wi的边;
同时建立一个终点,分别由各电影点连到终点一条流量为1,费用为0的边;
由于一个电影只能一个人观看,所以把电影点拆分成两个点,所有连到电影i的边全都连到i的汇点上,所有由电影i连出的边全都由i的出点连出,并且把每个i的汇点到出点连一条流量为1,费用为0的边;
把所有边的费用 * -1,求最小费用,然后对总最小费用 * -1,即得到最大费用;

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int tmax=450;
const int inf=0x3f3f3f3f;
int Start[tmax],End[tmax],wlike[tmax],op[tmax];
struct Edge{
    int from,to,cap,flow,cost;
};
vector<Edge> edges;
vector<int> G[tmax];
queue<int> Q;
int inq[tmax],d[tmax],p[tmax],a[tmax];
int n,wsad,mm;
void init()
{
    int i;
    for(i=0;i<=n;i++) G[i].clear();
    edges.clear();
    mm=0;
    return;
}
void add_edge(int from,int to,int cap,int cost)
{
    edges.push_back((Edge){from,to,cap,0,cost});
    edges.push_back((Edge){to,from,0,0,-cost});
    mm=edges.size();
    G[from].push_back(mm-2);
    G[to].push_back(mm-1);
    return;
}
bool BellmanFord(int s,int t,int &flow,int &cost)
{
    for(int i=0;i<=n;i++) d[i]=inf;
    memset(inq,0,sizeof(inq));
    d[s]=0;inq[s]=1;p[s]=0;a[s]=inf;
    Q.push(s);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        inq[u]=0;
        for(int i=0;i<G[u].size();i++)
        {
            Edge& e=edges[G[u][i]];
            if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
            {
                d[e.to]=d[u]+e.cost;
                p[e.to]=G[u][i];
                a[e.to]=min(a[u],e.cap-e.flow);
                if(!inq[e.to])
                {
                    Q.push(e.to);
                    inq[e.to]=1;
                }
            }
        }
    }
    if(d[t]==inf) return false;
    flow+=a[t];
    cost+=d[t]*a[t];
    int u=t;
    while(u!=s)
    {
        edges[p[u]].flow+=a[t];
        edges[p[u]^1].flow-=a[t];
        u=edges[p[u]].from;
    }
    //test();
    return true;
}
int Mincost(int s,int t)
{
    for(int i=0;i<edges.size();i++)
        edges[i].cost*=-1;
    int flow=0,cost=0;
    while(BellmanFord(s,t,flow,cost));
    return -cost;
}
int main()
{
    int T,i,j,hour,m,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d%d",&hour,&m,&k,&wsad);
        for(i=1;i<=m;i++)
            scanf("%d%d%d%d",&Start[i],&End[i],&wlike[i],&op[i]);
        for(i=1;i<=m;i++)
            for(j=i+1;j<=m;j++)
            {
                if(End[i]<=Start[j])
                {
                    if(op[i]!=op[j])
                        add_edge(i+m+1,j,1,wlike[j]);
                    else add_edge(i+m+1,j,1,wlike[j]-wsad);
                }
                else if(End[j]<=Start[i])
                {
                    if(op[i]!=op[j])
                        add_edge(j+m+1,i,1,wlike[i]);
                    else add_edge(j+m+1,i,1,wlike[i]-wsad);
                }
            }
        for(i=1;i<=m;i++)
            add_edge(0,i,1,wlike[i]);             //0汇点
        for(i=1;i<=m;i++)
            add_edge(i+m+1,m+1,1,0);             //m+1 终点
        n=m*2+5;
        add_edge(n,0,k,0);
        for(i=1;i<=m;i++)
            add_edge(i,i+m+1,1,0);
        printf("%d\n",Mincost(n,m+1));
        init();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jerry99s/article/details/81977832