裸的费用流。
源点向每件物品连边,容量为C[i], 费用为0。
每个人向汇点连S[i]+1条边,每条边的容量为T[i][j] - T[i][j-1], 费用为W[i][j]。
物品和员工之间直接按所给的矩阵连容量为无穷大的边。
结果要用long long 。
#include <iostream>
#include <queue>
#include <string.h>
#include <cstdio>
#define MAX 2010
#define MAXE 600010
using namespace std;
int maxData = 0x7fffffff;
queue<int> dl;
int head[MAX],cost[MAXE],net[MAXE],to[MAXE],cap[MAXE];
int cnt=1;
int map[300][300];
void add(int x,int y,int c,int z)
{
to[++cnt]=y;
cost[cnt]=z;
cap[cnt]=c;
net[cnt]=head[x];
head[x]=cnt;
}
int flow[MAX];
int pre[MAX];//前驱节点
int xb[MAX];//记录下标,便于修改容量
int n,m;
int mflow=0;//最大流
long long mcost=0;//最小费用
int dis[MAX];//记录从源点到当前节点的最小的费用值,学过最小路的都懂
int f[MAX];//标记是否在队列中
int ti[MAX];
int BFS(int s,int t)
{
memset(dis,127,sizeof(dis));//赋初值最大值
memset(f,0,sizeof(f));//赋值为0
int INF=dis[0];
while(!dl.empty())
dl.pop();
for(int i=1;i<=n;i++)
pre[i]=-1;//清空前驱节点
f[s]=1;
dis[s]=0;
pre[s]=0;
flow[s]=maxData;
dl.push(s);
while(!dl.empty())
{
int dd=dl.front();
dl.pop();
f[dd]=0;
for(int i=head[dd];i;i=net[i])
{
int tmp=to[i];
if(cap[i]>0&&dis[tmp]>dis[dd]+cost[i])//松弛操作
{
dis[tmp]=dis[dd]+cost[i];
pre[tmp]=dd;
xb[tmp]=i;
flow[tmp]=min(flow[dd],cap[i]);
if(!f[tmp]) f[tmp]=1,dl.push(tmp);
}
}
}
if(dis[t]>=INF) return 0;//成功找到了增广路
return 1;
}
void max_flow(int s,int t)
{
while(BFS(s,t))
{
int k=t;
while(k!=s)
{
cap[xb[k]]-=flow[t];
cap[xb[k]^1]+=flow[t];
k=pre[k];
}
mflow+=flow[t];
mcost+=flow[t]*dis[t];//流量乘以最小单位流量的费用即为最小费用
}
}
int main()
{
int s,t;
t=MAX-1;
scanf("%d%d",&n,&m);//n为人,m为产品
s=0;
int b=n+m;
for(int i=1;i<=n;i++)
add(s,i,maxData,0),add(i,s,0,0);
for(int i=1;i<=m;i++)
{
int c;
scanf("%d",&c);
add(i+n,t,c,0);
add(t,i+n,0,0);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&map[i][j]);
for(int i=1;i<=n;i++)
{
int ss;
scanf("%d",&ss);
for(int j=1;j<=ss;j++)
scanf("%d",&ti[j]);
ti[ss+1]=maxData;
for(int j=1;j<=ss+1;j++)
{
int x1;
scanf("%d",&x1);
add(i,++b,ti[j]-ti[j-1],x1);
add(b,i,maxData,-x1);
for(int k=1;k<=m;k++)
if(map[i][k])
add(b,k+n,maxData,0),add(k+n,b,0,0);
}
}
max_flow(s,t);
printf("%lld",mcost);
return 0;
}