HDU 6126 Give out candies(最小割)

Give out candies

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 ith line contains m positive integers, the jth 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.

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

2017 Multi-University Training Contest - Team 7


题意:有n个小朋友,标号为1到n,你要给每个小朋友至少1个且至多m个的糖果。小朋友们共提出k个要求,每个要求包括三个整数x,y,z,表示x号小朋友得到的糖果数减去y号小朋友得到的糖果数,结果应当不大于z。如果你给i号小朋友j颗糖果,他会获得w[i,j]的满意度,你需要最大化所有小朋友的满意度之和。


题解:用i.j这点表示给第i个孩子至少j块糖,当这个点属于S集合时所代表条件成立。然后i.j->i.j+1连1000-wi,j,i.m向T连1000-wi,m,S向i.1连inf。如果存在ax-ay>=z,x.k->y.k+z连inf。跑最小割,再用n*1000减掉答案


#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<math.h>
#include<queue>
#define INF 1e9
using namespace std;
int n;
struct edge
{
    int to,cap,rev;
};
vector<edge>g[3000];

void add_edge(int from,int to,int cap)
{
    g[from].push_back((edge){to,cap,g[to].size()});
    g[to].push_back((edge){from,0,g[from].size()-1});
}
int level[3000];
int iter[3000];
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue<int>que;
    level[s]=0;
    que.push(s);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=0;i<g[v].size();i++)
        {
            edge &e=g[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v];i<g[v].size();i++)
    {
        edge &e=g[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                g[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)
{
    int flow=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)
            flow+=f;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m,k;
        for(int i=0;i<3000;i++)
            g[i].clear();
        scanf("%d%d%d",&n,&m,&k);
        int x;
        int t=n*m+5;
        int s=0;
        for(int i=0;i<n;i++)
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&x);
                if(j==m) add_edge(i*m+j,t,10000-x);
                else add_edge(i*m+j,i*m+j+1,10000-x);
                if(j==1) add_edge(s,i*m+j,INF);
            }
        int y,z;
        for(int i=0;i<k;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            x--;
            y--;
            int last=0;
            for(int j =1;j<=m;j++)
                if(j-z>=1&&j-z<=m)
                {
                    add_edge(x*m+j,y*m+j-z,INF);
                    last=j;
                }
            if(last+1-z>m&&last+1<=m)
                add_edge(x*m+last+1,t,INF);
        }
        int res=max_flow(0,t);
        if(res>=1e9)
        {
            cout<<"-1\n";
            continue;
        }
        res=10000*n-res;
       cout<<res<<endl;
    }

    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值