题目
思路
观察到题目中的一个美好性质:
W
i
,
j
W_{i,j}
Wi,j随j递增。
我们是spfa贪心求解,所以我们可以这样建边:
s到每个工作连容量
C
i
C_i
Ci,费用0的边。
每个工作和人按给的可达矩阵建容量1e8(inf),费用0的边。
每个人向t连容量为分段长度,费用为分段愤怒的边。
W
i
,
j
W_{i,j}
Wi,j随j递增可以保证我们在
W
i
,
j
W_{i,j}
Wi,j被流过时,
W
i
,
j
−
1
W_{i,j-1}
Wi,j−1一定被流满了。
接下来Dinic+spfa。
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
//When I wrote this code,God and I unterstood what was I doing
int n,s,t,x,y,tot=2,head[5001],dep[5001],fy;
bool book[5001];
long long w,ans,in[5001],ans2;
long long mn(long long x,long long y)
{
return (x>y?y:x);
}
struct f{
int to,net;
long long w,fy;
} a[1000011];
int b[1000011];
void add(int x,int y,long long w,long long fy)
{
a[tot].to=y,a[tot].w=w,a[tot].net=head[x],a[tot].fy=fy,head[x]=tot++;
return;
}
bool spfa()
{
memset(dep,0x3f,sizeof(dep));
memset(book,0,sizeof(book));
queue<int> u;
u.push(s);
book[s]=1,dep[s]=0,in[s]=0x7fffffff;
while (u.size())
{
y=u.front();
u.pop();
book[y]=0;
for (int j=head[y];j;j=a[j].net)
{
if (a[j].w!=0&&dep[y]+a[j].fy<dep[a[j].to])
{
dep[a[j].to]=dep[y]+a[j].fy;//记录单价和
in[a[j].to]=min(in[y],a[j].w);
b[a[j].to]=j;
if (!book[a[j].to]) book[a[j].to]=1,u.push(a[j].to);
}
}
}
return dep[t]!=1061109567;
}
void dfs()
{
x=t;
ans+=in[t];
ans2+=dep[t]*in[t];
while (x!=s)
{
a[b[x]].w-=in[t],a[b[x]^1].w+=in[t],x=a[b[x]^1].to;
}//清空增广路
return;
}
int wj[5001],m;
int main()
{
scanf("%d%d",&m,&n);
s=n+m+1,t=s+1;
for (int i=1;i<=n;i++)
{
scanf("%d",&w);
add(s,i,w,0);
add(i,s,0,0);
}
for (int i=1;i<=m;i++) for (int j=1;j<=n;j++)
{
scanf("%d",&x);
if (x)
{
add(j,i+n,1e8,0);
add(i+n,j,0,0);
}
}
for (int i=1;i<=m;i++)
{
scanf("%d",&x);
for (int j=1;j<=x;j++)
{
scanf("%d",&wj[j]);
}
wj[x+1]=1e8;
for (int j=1;j<=x+1;j++)
{
scanf("%d",&y);
add(i+n,t,wj[j]-wj[j-1],y);
add(t,i+n,0,-y);
}
}
while (spfa())
{
dfs();
}
cout<<ans2;
return 0;
}
//Now,only God know
//但行好事,莫问前程