原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6437
题目大意:
n个时刻,m个节目,K个人,W为连续看相同类型节目减少的权值
对每个节目,时间段为从 S时 到 T时 ,可以获得w权值,节目类型为op,op只有两种,0和1
同一节目只能允许一个人观看
求所有人权值之和的最大值
题解:
构建
对源点 源点 -> k个人 k条路 容量1 权值0
对每个人 人 -> m个节目 m条路 容量1 权值0
对每个节目 将节目拆成两个点 节目_1 -> 节目_2 -> 汇点 前者容量1 权值w 后者容量1 权值0
对节目与节目之间 第i个节目_2 -> 第j个节目_1 条件:i_r<=j_l 容量1 权值(0或w)
之后走一遍最小费用流
AC代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 200100;
const int INF = 0x3f3f3f3f;
struct node{
int u,v,w,c;
int Next;
node(int _u=0,int _v=0,int _w=0,int _c=0,int _Next=0){
u = _u;v = _v;w = _w;c = _c;
Next = _Next;
}
}edge[N];
struct mov{
int l,r,w,op;
}mov[300];
int cnt=0,Next[N];
int dis[N],vis[N],pre[N];
int source,sink;
void add(int u,int v,int w,int c)
{
edge[cnt] = node(u,v,w,c,Next[u]);
Next[u] = cnt++;
edge[cnt] = node(v,u,0,-c,Next[v]);
Next[v] = cnt++;
}
bool spfa()
{
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
int i;
dis[source] = 0;
vis[source] = 1;
queue<int> q;
q.push(source);
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for(i=Next[u];i!=-1;i=edge[i].Next)
{
int v,w,c;
v = edge[i].v;
w = edge[i].w;
c = edge[i].c;
if(w>0 && dis[v]>dis[u]+c)
{
dis[v] = dis[u]+c;
pre[v] = i;
if(!vis[v])
{
q.push(v);
vis[v] = 1;
}
}
}
}
return dis[sink] != INF;
}
int mcmf()
{
int full = 0;
int cost = 0;
int i,j;
while(spfa())
{
int mi = INF;
for(i=sink;i!=source;i=edge[pre[i]].u)
mi = min(mi,edge[pre[i]].w);
for(i=sink;i!=source;i=edge[pre[i]].u)
{
//uv vu 存在相邻的位置
edge[pre[i]].w -= mi;
edge[pre[i]^1].w += mi;
}
cost += mi*dis[sink];
full += mi;
}
return cost;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,k,w;
int i,j;
cnt = 0;
memset(Next,-1,sizeof(Next));
scanf("%d%d%d%d",&n,&m,&k,&w);
for(i=1;i<=m;i++)
scanf("%d%d%d%d",&mov[i].l,&mov[i].r,&mov[i].w,&mov[i].op);
/*************************************/
source = 0, sink = 2*m+k+1; //源点 汇点
//点与点之间 点到汇点
for(i=1;i<=m;i++)
{
add(i,i+m,1,-mov[i].w);
add(i+m,sink,1,0);
for(j=1;j<=m;j++)
{
if(mov[i].r <= mov[j].l)
{
if(mov[i].op == mov[j].op)
add(i+m,j,1,w);
else
add(i+m,j,1,0);
}
}
}
//源点到人 人到所有节目
for(i=1;i<=k;i++)
{
add(source,i+2*m,1,0);
for(j=1;j<=m;j++)
add(i+2*m,j,1,0);
}
/**********以上将图构建完成***********/
printf("%d\n",-mcmf());
}
return 0;
}