Description
小K和同学们期待已久的暑假即将到来。然而小K的班主任兼德育处主任却莫名失踪了一个月。据小道消息,他在高考后才会出现。但现在德育处有诸多繁杂的工作,确定每个班的“三好学生”便是最令人头痛的。
HY中学的大Boss圆规要求N个班的班主任按照学生的综合素质推荐学生。但他深深地知道,每个班主任都会无一例外地使用xls把M名学生数次月考成绩相加排序,然后从高到底依次录取。圆规知道每个班学生成绩的排序和每个学生得到该荣誉的“负”能量Aij。显然,“负”能量也是有正有负的。他不希望有些学生拿到“三好学生”后依然肆无忌惮地拔掉教室里监控的探头,或是在晚餐时间在篮球场上尽情玩耍(这在HY中学是会被通报批评的)。他希望能够多发扬正能量。
圆规从不在乎“三好学生”的数量,但是他却不得不考虑学生的感受。学生在学生会上
(1)提出了K条无理的要求,每条要求对于班级u、v,要求班级u的三好学生数量Su和班级v三好学生数量Sv,满足Su-Sv<=w。
(2)提出每个班至少一张奖状。
鉴于HY中学的高一高二学生在5月下旬某一个酷热的晚上,忍无可忍围起了整栋教学楼,并且齐声高声叫喊:“开空调!”但学校善后处理十分不得力。圆规决定全盘接受学生的建议,以平息学生的怒气。但是,他还是想知道最小的负能量。
Input
第1行 为三个数N、M、K如题意所示。
第2-N+1行,每行M个数,表示按成绩从高到底排序的每个学生的“负”能量大小。
第N+2-N+K+1行,每行三个数u、v、w如题意所示。
Output
最小的负能量。
Sample Input
3 4 3 13 -4 -1 -2 1 -2 3 1 -3 4 2 1 2 3 0 3 2 0 1 2 1
Sample Output
7
Data Constraint
20%的数据 n,m<=10;
50%的数据 n,m<=30,K<=500
70%的数据 n,m<=50,K<=2000
100%的数据 n<=900,m<=60,K<=20000,Aij的绝对值小于1000,w<=1000。
Solution
可以转化为网络流模型。
建立源点和汇点,每班第一人从源点连一条inf容量的边,每班每个同学向后一个同学连边,边权为前i个同学的负能量之和。每班最后一个人向汇点同样连这个班所有人的负能量之和。因为要求每个班必须选,因此不能割从源点到第一个人的边,除此之外,每割一条边表示选了这个班的前i个人。对于一个限制条件,班级v最多能比班级u少选w个人。也就是说割了班级u的第i点的边后,班级v的第i-w的点之前的边就都不能割,那么我们从u班的i这个点向v班i-w连一条inf的边即可,最后跑一边最小割就是答案了。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 2147483647
#define N 910
#define M 3100000
using namespace std;
I rd(I &x){
x=0;I w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
x*=w;
}
I n,m,k,tot,mi,S,T,a[N][100],id[N][100],d[N*110],q[N*110],ans,flow;
I t[M],nx[M],l[N*100],s[M];
void add(I x,I y,I z){
t[++t[0]]=y,nx[t[0]]=l[x],l[x]=t[0],s[t[0]]=z;
t[++t[0]]=x,nx[t[0]]=l[y],l[y]=t[0],s[t[0]]=0;
}
I bfs(){
mem(d,0);
q[1]=S;I i=0,j=1;d[S]=1;
while(i<j){
I x=q[++i];
for(I k=l[x];k;k=nx[k]) if(s[k]&&!d[t[k]]){
q[++j]=t[k];
d[t[k]]=d[x]+1;
if(t[k]==T) return 1;
}
}
return 0;
}
I dinic(I x,I fl){
if(x==T) return fl;
I r=fl,st;
for(I k=l[x];k&&r;k=nx[k]) if(s[k]&&d[t[k]]==d[x]+1){
st=dinic(t[k],min(r,s[k]));
if(!st) d[t[k]]=0;
s[k]-=st;s[k^1]+=st;
r-=st;
}
return fl-r;
}
I main(){
freopen("honor.in","r",stdin);
freopen("honor.out","w",stdout);
rd(n),rd(m),rd(k);
F(i,1,n){
F(j,1,m){
rd(a[i][j]);a[i][j]+=a[i][j-1];
mi=min(mi,a[i][j]);
id[i][j]=++tot;
}
}
S=++tot,T=++tot;t[0]=1;
F(i,1,n){
add(S,id[i][1],inf);
F(j,1,m){
a[i][j]-=mi;
if(j==m)add(id[i][j],T,a[i][j]);
else add(id[i][j],id[i][j+1],a[i][j]);
}
}
I x,y,z;
while(k--){
rd(x),rd(y),rd(z);
F(i,1,m) if(i-z) add(id[x][i],id[y][i-z],inf);
}
flow=0;
while(bfs()){
while(flow=dinic(S,inf)) ans+=flow;
}
printf("%d\n",ans+mi*n);
return 0;
}