题目描述
暑假里,总有某些同学由于贪玩而忘记做作业。这些人往往要等到暑假快结束时才想起堆积如山的作业,但在这最后几天的时间里把这些作业做完已经不太现实了,于是“志同道合”的他们想出了一个妙招。
假设现在有n科作业,他们把第i科作业按作业量平均分成ai份,他们总共有m个人,第j个人只愿意做其中任意的bj份作业,而且我们知道ai的和等于bj的和,以及把第i科作业的其中一份给第j个人做的时间是ci,j。现在他们想分配下各自的任务,一起把作业做完,然后再%#^&%^&#%%&^
现在的问题来了,他们希望所有人做作业的总时间的和最小,你能帮助他们解决问题吗?
Input
输入文件的第一行有两个n,m表示有多少科作业和多少个人,第二行有n个数依次表示ai,第三行有m个数依次表示bj,最后n行,每行m个数表示ci,j。
Output
输出文件包含一行为最少的时间总和。
Sample Input
2 2
3 5
5 3
1 2
2 1
Sample Output
10
【样例解释】
第1个人做完所有的第1科作业以及第2科作业的其中2份,第2个人把第2科另外3份做完。
Data Constraint
第一个点 n<=5 m<=5 ai,bi<=15 sum(ai)<=20
第二个点 n<=10 m<=10 ai,bi<=20 sum(ai)<=100
第三个点 n<=30 m<=30 ai,bi<=600 sum(ai)<=10000
第四个点到第十个点 n<=200 m<=200 ai,bi<=10000 sum(ai)<=1000000
分析
容易看出费用流,但是时限500ms跑不过去,加了一个玄学优化:动态加边可以优化1500ms,从而AC
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
const int N=501;
const int oo=1061109567;
using namespace std;
struct Edge {
int u,v,c,w,nx;
}g[2*N*N];
struct Edge_notadd {
int v,c;
}e[N][N];
int ecnt[N],pt[N];
int cnt=1,list[N];
int n,m,s,t;
int d[N],f[N];
int ans;
bool Cmp(Edge_notadd a,Edge_notadd b) {
return a.c<b.c;
}
void Add(int u,int v,int c,int w) {
g[++cnt].u=u;g[cnt].v=v;g[cnt].c=c;g[cnt].w=w;g[cnt].nx=list[u];list[u]=cnt;
g[++cnt].u=v;g[cnt].v=u;g[cnt].c=0;g[cnt].w=-w;g[cnt].nx=list[v];list[v]=cnt;
}
bool Spfa() {
queue<int> q;
bool b[N];
while (!q.empty()) q.pop();
q.push(s);
memset(d,0x3f,sizeof d);memset(b,0,sizeof b);memset(f,0,sizeof f);
d[s]=0;b[s]=1;
while (!q.empty()) {
int u=q.front();q.pop();
for (int i=list[u];i;i=g[i].nx)
if (g[i].c&&d[g[i].v]>d[u]+g[i].w) {
d[g[i].v]=d[u]+g[i].w;
f[g[i].v]=i;
if (!b[g[i].v])
q.push(g[i].v);
b[g[i].v]=1;
}
b[u]=0;
}
return d[t]<oo;
}
void Mcf() {
int x=t,cost=d[t],mf=oo;
while (f[x]) {
x=f[x];
mf=min(mf,g[x].c);
x=g[x].u;
}
ans+=cost*mf;x=t;
while (f[x]) {
x=f[x];
g[x].c-=mf;
g[x^1].c+=mf;
x=g[x].u;
}
int i;
rep(i,1,n)
while (!g[pt[e[i][ecnt[i]].v]].c&&ecnt[i]<m) {
ecnt[i]++;
Add(i,e[i][ecnt[i]].v,oo,e[i][ecnt[i]].c);
}
}
void Dinic() {
while (Spfa())
Mcf();
}
int main() {
int i,j;
scanf("%d%d",&n,&m);
s=n+m+1;t=n+m+2;
rep(i,1,n) {
int w;scanf("%d",&w);
Add(s,i,w,0);
}
rep(i,1,m) {
int w;scanf("%d",&w);
Add(n+i,t,w,0);
pt[n+i]=cnt-1;
}
rep(i,1,n)
{
rep(j,1,m)
{
int w;scanf("%d",&w);
e[i][j].v=n+j;
e[i][j].c=w;
}
sort(e[i]+1,e[i]+m+1,Cmp);
Add(i,e[i][1].v,oo,e[i][1].c);
ecnt[i]=1;
}
Dinic();
printf("%d",ans);
}