Give out candies 最小割

2023-10-05 13:59
文章标签 最小 give candies

本文主要是介绍Give out candies 最小割,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Give out candies

问题描述

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.( 0 < wi,j <=1000 )

输入格式

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.

输出格式

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.

样例输入

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

样例输出

2
7


题意:
n个孩子,每个孩子要分到至少1个,至多m个糖果。第i个孩子分到j个糖果会对答案有wi,j的贡献。在满足形如“x y z”,即第x个孩子的糖果不能比第y个孩子的糖果多z个以上的k个限制下,求答案的最大值。


题解:
观察到数据范围非常小,考虑爆搜网络流。

根据数据范围,不难想到把每个孩子拆成m个点。只不过(i,j)不是表示i号孩子恰得到了j颗糖,而是i号孩子至少得到了j颗糖

为什么这么定义?因为这样才能向最小割模型转化。不考虑限制的情况下,先这样建图:

用(i,j)表示i号孩子至少得到j颗糖。
对于任意0 < j < m,连接(i,j)和(i,j+1),容量为-wi,j。
连接源点和(i,1),容量为inf。
连接(i,m)和汇点,容量为-wi,m。

直观点就是这个样子:
这里写图片描述

容易看出,在没有限制的条件下,上图的最小割的相反数就是答案最大值。与S在一个集合里的点,其代表的条件是被满足的。这就解释了(i,j)为什么这样定义。

由于网络流算法不允许容量为负,那么有一个经典的处理方法:将每条边加上一个相等的足够大的数将边权全部转为非负,这样不会影响割边的选取。由于本题中wi,j最大为1000,因此对上述的每条边容量加上1000,答案就用1000*n减去最小割即可。

没有限制的条件下这样的做法是很智障的,现在考虑加上限制后怎么做。本题中有一个比较巧妙的建图方式。考虑下面的图:
这里写图片描述
上图有一个性质:
考虑最小割。在正常情况下,割掉了蓝边之后,在S->a->T的这一支上就一定不会割掉绿色部分的边。原因很简单:如果割掉绿色部分的边,那么a就在T集合中,而因为b在S集合中,因此b到a的边会被割掉。这条边的容量是inf,这样一定不是最小割。

那么不正常的情况是什么?当然是无解的情况,即用最小割算法都会割掉inf边的情况。

当然你也可以用差分约束系统判无解。

套用到本题上,就是对于一个约束”x y z”,将(x,j)连一条到(y,j-z),容量为inf的边。如果下标越界,相应地连向源点或汇点。其余部分按照之前的方式建图即可。


代码:

#include<stdio.h>
#include<algorithm>
#include<cstring>
#define MAXN 5000
#define MAXM 50000
using namespace std;int N,M,K,Ans,w[55][55],id[55][55];int nex[MAXM],en[MAXM],G[MAXM],las[MAXN],st[MAXN],tot;
void Add(int x,int y,int g){en[++tot]=y;nex[tot]=las[x];las[x]=st[x]=tot;G[tot]=g;
}
void Link(int x,int y,int g){Add(x,y,g);Add(y,x,0);
}int dis[MAXN],Cnt[MAXN],S,P,T;
int SAP(int x,int flow){if(x==T)return flow;int i,y,d=0,tmp;for(i=st[x];i;i=nex[i]){y=en[i];if(G[i]&&dis[x]==dis[y]+1){tmp=SAP(y,min(flow-d,G[i]));d+=tmp;G[i]-=tmp;G[i^1]+=tmp;st[x]=i;if(d==flow||dis[S]>=P)return d;}}st[x]=las[x];if(--Cnt[dis[x]]==0)dis[S]=P;Cnt[++dis[x]]++;return d;
}void Clear(){tot=1;memset(las,0,sizeof(las));memset(Cnt,0,sizeof(Cnt));memset(dis,0,sizeof(dis));
}int main(){
int Q,i,j,k,x,y,z;scanf("%d",&Q);
while(Q--){Clear();scanf("%d%d%d",&N,&M,&K);for(i=1,k=0;i<=N;i++)for(j=1;j<=M;j++)scanf("%d",&w[i][j]),id[i][j]=++k;S=k+1;T=P=S+1;for(i=1;i<=N;i++)for(j=1;j<M;j++)Link(id[i][j],id[i][j+1],1000-w[i][j]);for(i=1;i<=N;i++)Link(id[i][M],T,1000-w[i][M]),Link(S,id[i][1],1e9);for(i=1;i<=K;i++){scanf("%d%d%d",&x,&y,&z);for(j=1;j<=M;j++){if(j-z<=0)Link(id[x][j],S,1e9);else if(j-z>M)Link(id[x][j],T,1e9);else Link(id[x][j],id[y][j-z],1e9);}}Ans=N*1000;while(dis[S]<=P)Ans-=SAP(S,1e9);if(Ans<0)puts("-1");else printf("%d\n",Ans);
}
}

这篇关于Give out candies 最小割的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/151324

相关文章

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

poj 1734 (floyd求最小环并打印路径)

题意: 求图中的一个最小环,并打印路径。 解析: ans 保存最小环长度。 一直wa,最后终于找到原因,inf开太大爆掉了。。。 虽然0x3f3f3f3f用memset好用,但是还是有局限性。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#incl

hdu 1102 uva 10397(最小生成树prim)

hdu 1102: 题意: 给一个邻接矩阵,给一些村庄间已经修的路,问最小生成树。 解析: 把已经修的路的权值改为0,套个prim()。 注意prim 最外层循坏为n-1。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstri

poj 2175 最小费用最大流TLE

题意: 一条街上有n个大楼,坐标为xi,yi,bi个人在里面工作。 然后防空洞的坐标为pj,qj,可以容纳cj个人。 从大楼i中的人到防空洞j去避难所需的时间为 abs(xi - pi) + (yi - qi) + 1。 现在设计了一个避难计划,指定从大楼i到防空洞j避难的人数 eij。 判断如果按照原计划进行,所有人避难所用的时间总和是不是最小的。 若是,输出“OPETIMAL",若

poj 2135 有流量限制的最小费用最大流

题意: 农场里有n块地,其中约翰的家在1号地,二n号地有个很大的仓库。 农场有M条道路(双向),道路i连接着ai号地和bi号地,长度为ci。 约翰希望按照从家里出发,经过若干块地后到达仓库,然后再返回家中的顺序带朋友参观。 如果要求往返不能经过同一条路两次,求参观路线总长度的最小值。 解析: 如果只考虑去或者回的情况,问题只不过是无向图中两点之间的最短路问题。 但是现在要去要回

poj 3422 有流量限制的最小费用流 反用求最大 + 拆点

题意: 给一个n*n(50 * 50) 的数字迷宫,从左上点开始走,走到右下点。 每次只能往右移一格,或者往下移一格。 每个格子,第一次到达时可以获得格子对应的数字作为奖励,再次到达则没有奖励。 问走k次这个迷宫,最大能获得多少奖励。 解析: 拆点,拿样例来说明: 3 2 1 2 3 0 2 1 1 4 2 3*3的数字迷宫,走两次最大能获得多少奖励。 将每个点拆成两个

poj 2195 bfs+有流量限制的最小费用流

题意: 给一张n * m(100 * 100)的图,图中” . " 代表空地, “ M ” 代表人, “ H ” 代表家。 现在,要你安排每个人从他所在的地方移动到家里,每移动一格的消耗是1,求最小的消耗。 人可以移动到家的那一格但是不进去。 解析: 先用bfs搞出每个M与每个H的距离。 然后就是网络流的建图过程了,先抽象出源点s和汇点t。 令源点与每个人相连,容量为1,费用为

poj 3068 有流量限制的最小费用网络流

题意: m条有向边连接了n个仓库,每条边都有一定费用。 将两种危险品从0运到n-1,除了起点和终点外,危险品不能放在一起,也不能走相同的路径。 求最小的费用是多少。 解析: 抽象出一个源点s一个汇点t,源点与0相连,费用为0,容量为2。 汇点与n - 1相连,费用为0,容量为2。 每条边之间也相连,费用为每条边的费用,容量为1。 建图完毕之后,求一条流量为2的最小费用流就行了