Give out candies
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 517 Accepted Submission(s): 170
Problem Description
There are
n
children numbered
1
to
n
, and HazelFan's task is to give out candies to the children. Each children must be given at least
1
and at most
m
candies. The children raised
k
pieces of requirements, and every piece includes three integers
x,y,z
, means that the number of candies given to the child numbered
x
, subtract the number of candies given to the child number
y
, the result should not be more than
z
. Besides, if the child numbered
i
is given
j
candies, he or she will get
wi,j
satisfaction score, now you need to help HazelFan maximize the sum of the satisfaction scores of these children.
Input
The first line contains a positive integer
T(1≤T≤5)
, denoting the number of test cases.
For each test case:
The first line contain three positive integers n,m,k(1≤n,m≤50,1≤k≤150) .
The next n lines, the i th line contains m positive integers, the j th integer denotes wi,j .
The next k lines, each line contains three integers x,y,z(1≤x,y≤n,∣z∣<233) , denoting a piece of requirement.
For each test case:
The first line contain three positive integers n,m,k(1≤n,m≤50,1≤k≤150) .
The next n lines, the i th line contains m positive integers, the j th integer denotes wi,j .
The next k lines, each line contains three integers x,y,z(1≤x,y≤n,∣z∣<233) , denoting a piece of requirement.
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer. Particularly, if there is no way to give out candies, print -1.
A single line contains a nonnegative integer, denoting the answer. Particularly, if there is no way to give out candies, print -1.
Sample Input
2 2 1 1 1 1 1 2 1 3 3 2 1 2 3 2 3 1 3 1 2 1 2 0 2 3 0
Sample Output
2 7
Source
很巧妙的一个建图
此时应上ACM真有意思的表情包
n个人分糖,第i个人得到j个糖的收益是Wij,可以分得的糖果数是[1,m]。有k个限制,要求第X个人的糖数量和第Y个人的糖数量满足:
xi-yi<=zi
问最大收益。
这题求最大值,怎么会有最小割呢?
其实是把边的流量取反,但跑最大流算法的时候流量不可能是负的,于是我们给流量加上一个固定值使得流量为正。
如果不考虑限制条件,设Ai,j表示第i个人拿j个糖的点,则应该把Ai,j和Ai,j+1连上流量MAX-Wij, Ai,m和汇点连上流量为MAX-Ai,m, 源点和Ai,1连上流量inf(inf>>MAX)的边,此时最小割s即最优分法,答案是n*MAX-s。
对于某个限制条件Xi-Yi<=Zi,可以把所有Ax,j和Bx,j-z之间连上流量inf的边,这样,当不满足限制的割边发生时,必定要割某条流量为inf的边。
若最后跑出的最小割比inf大则说明不能满足所有限制条件,则无解,否则答案就是刚刚所提到的n*MAX-s.
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=55,maxk=100005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int a[maxn][maxn];
int head[maxn*maxn],dist[maxn*maxn],current[maxn*maxn];
int num;
struct Edge {
int from,to,flow,pre;
};
Edge edge[maxk];
void addedge(int from,int to,int flow) {
edge[num]=(Edge){from,to,flow,head[from]};
head[from]=num++;
edge[num]=(Edge){to,from,0,head[to]};
head[to]=num++;
}
bool bfs (int n) {
queue<int> q;
q.push(0);
memset(dist,-1,sizeof(dist));
dist[0]=0;
while (!q.empty()) {
int now=q.front();
q.pop();
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (dist[to]==-1&&edge[i].flow>0) {
dist[to]=dist[now]+1;
q.push(to);
}
}
}
return dist[n]!=-1;
}
int dfs(int now,int flow,int n) {
int f;
if (now==n) return flow;
for (int i=current[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
current[now]=i;
if (dist[now]+1==dist[to]&&edge[i].flow>0&&
(f=dfs(to,min(flow,edge[i].flow),n))) {
edge[i].flow-=f;
edge[i^1].flow+=f;
return f;
}
}
return 0;
}
int dinic(int n) {
int sum=0,f;
while (bfs(n)) {
memcpy(current,head,sizeof(head));
while (f=dfs(0,inf,n)) sum+=f;
}
return sum;
}
int main() {
int cas;
scanf("%d",&cas);
while (cas--) {
int n,m,k,i,j,x,y,z;
memset(head,-1,sizeof(head));
num=0;
scanf("%d%d%d",&n,&m,&k);
for (i=1;i<=n;i++) {
scanf("%d",&a[i][1]);
addedge(0,(i-1)*m+1,1e7);
for (j=2;j<=m;j++) {
scanf("%d",&a[i][j]);
addedge((i-1)*m+j-1,(i-1)*m+j,1000-a[i][j-1]);
}
addedge(i*m,n*m+1,1000-a[i][m]);
}
for (i=1;i<=k;i++) {
scanf("%d%d%d",&x,&y,&z);
for (j=max(z+1,1);j<=m&&j-z<=m;j++) {
addedge((x-1)*m+j,(y-1)*m+j-z,1e7);
}
if (j-z>m&&j<=m)
addedge((x-1)*m+j,n*m+1,1e7);
}
int ans=dinic(n*m+1);
if (ans>1e7) printf("-1\n"); else printf("%d\n",n*1000-ans);
}
return 0;
}