HDU-6126 Give out candies(最小割)
来源:互联网 发布:滨州行知中学电话 编辑:程序博客网 时间:2024/06/08 01:04
传送门:HDU-6126
有n个小朋友,标号为1到n,你要给每个小朋友至少1个且至多m个的糖果。小朋友们共提出k个要求,每个要求包括三个整数x,y,z,表示x号小朋友得到的糖果数减去y号小朋友得到的糖果数,结果应当不大于z。如果你给i号小朋友j颗糖果,他会获得wi,j的满意度,你需要最大化所有小朋友的满意度之和。1≤n,m≤50,1≤k≤150,1≤wi,j≤103。
题解:网络流最小割
首先考虑没有限制的情况:对于每个人,当然要选取愉悦值最高的情况,如果要用最大流表示,用(i,j)表示第i个人获得j个糖果,愉悦值为w(i,j),边的容量就可以设为F-w(i,j),F为一个足够大的正整数,将(i,j)->(i,j+1)用这条边连接起来,如果这条边是最小割,就表示送给第i个人j个糖果的愉悦值是最高的。再让源点与(i,1)连一条容量为正无穷的边,(i,m)与汇点连容量为F-w(i,m)的边
再考虑有限制的情况:发给第x个人的糖果数-发给第y个人的糖果数不能大于z(这里只考虑z>0的情况)
设第i个人的糖果数为a[i],则a[x]-a[y]<=z --> a[x]-z<=a[y]
因此可以转化为:如果x拿了a[x]个糖果,那么y的糖果就不能少于a[x]-z
要如何表示这种冲突呢?首先肯定要想到建无限容量的边,我们将(x,j)->(y,j-z)连一条容量为正无穷的边,
根据容量无穷大边的性质,在这条边的两端至少有一个割点(不存在x的割在某个大于j的点,y的割在某个小于j-z的点)
当限制条件发生冲突时,比如a[x]<=a[y],a[y]+1<=a[x],这样源点与汇点之间会有一条由正无穷的边构成的路径,因此只要流量为正无穷时,就表示发生了冲突,输出-1
#include<bits/stdc++.h>#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;typedef long long LL;typedef pair<int, int> PII;const LL mod = 1e9 + 7;int n, m, k;const int inf = 0x3f3f3f3f;const int MX = 2555;const int MXE = 4 * MX * MX;struct MaxFlow { struct Edge { int v, w, nxt; } edge[MXE]; int tot, num, s, t; int head[MX]; void init() { memset(head, -1, sizeof(head)); tot = 0; } void add(int u, int v, int w) { edge[tot].v = v; edge[tot].w = w; edge[tot].nxt = head[u]; head[u] = tot++; edge[tot].v = u; edge[tot].w = 0; edge[tot].nxt = head[v]; head[v] = tot++; } int d[MX], vis[MX], gap[MX]; void bfs() { memset(d, 0, sizeof(d)); memset(gap, 0, sizeof(gap)); memset(vis, 0, sizeof(vis)); queue<int>q; q.push(t); vis[t] = 1; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; ~i; i = edge[i].nxt) { int v = edge[i].v; if (!vis[v]) { d[v] = d[u] + 1; gap[d[v]]++; q.push(v); vis[v] = 1; } } } } int last[MX]; int dfs(int u, int f) { if (u == t) return f; int sap = 0; for (int i = last[u]; ~i; i = edge[i].nxt) { int v = edge[i].v; if (edge[i].w > 0 && d[u] == d[v] + 1) { last[u] = i; int tmp = dfs(v, min(f - sap, edge[i].w)); edge[i].w -= tmp; edge[i ^ 1].w += tmp; sap += tmp; if (sap == f) return sap; } } if (d[s] >= num) return sap; if (!(--gap[d[u]])) d[s] = num; ++gap[++d[u]]; last[u] = head[u]; return sap; } int solve(int st, int ed, int n) { int flow = 0; num = n; s = st; t = ed; bfs(); memcpy(last, head, sizeof(head)); while (d[s] < num) flow += dfs(s, inf); return flow; }} F;int code(int i, int j) { if (j == m + 1) return n * m + 1; return (i - 1) * m + j;}int main() { int T; //freopen("in.txt", "r", stdin); scanf("%d", &T); while (T--) { scanf("%d%d%d", &n, &m, &k); F.init(); for (int i = 1; i <= n; i++) { F.add(0, code(i, 1), inf); for (int j = 1, w; j <= m; j++) { scanf("%d", &w); F.add(code(i, j), code(i, j + 1), 1000 - w); } } for (int i = 1, x, y, z; i <= k; i++) { scanf("%d%d%d", &x, &y, &z); for (int j = 1; j <= m; j++) { if (j - z > 0) F.add(code(x, j), code(y, min(j - z, m + 1)), inf); } } int cnt = F.solve(0, n * m + 1, n * m + 2); if (cnt >= inf) printf("-1\n"); else printf("%d\n", n * 1000 - cnt); } return 0;}
- HDU 6126 Give out candies 最小割
- HDU-6126 Give out candies(最小割)
- HDU 6126 Give out candies(最小割)
- HDU 6126 Give out candies(最小割-Dinic)
- HDU 6126 Give out candies (贼巧妙的最小割)
- [HDU 6126] Give out candies
- hdu6126 Give out candies(SPFA+Dinic)
- hdu 3046(最小割)
- hdu 3251(最小割)
- hdu 3452(最小割)
- hdu 4289(最小割)
- 平面图ST最小割(hdu 3870)
- 最小割集 hdu 3002 ( 模板)
- HDU 4289 Control(最小割)
- HDU 3820 Golden Eggs (最小割)
- hdu 3657 Game (最小割)
- hdu 3491 Thieves(最小割)
- hdu 3035 War(平面图最小割)
- 大数据Spark企业级实战版【学习笔记】----Spark Shark& Spark SQL
- 通过使用Socket来扫描获取手机中可使用的端口
- Application Programming Interfaces -- 1
- hdu 5703 Desert 水题
- 一键读取Txt、Excel等表格配置【源码+原理】
- HDU-6126 Give out candies(最小割)
- lintcode --最小路径和
- POJ 2752 Seek the Name, Seek the Fame (KMP)
- mongoDB 安装和启动
- 1.16 C# 委托(下)
- hdu 3530 Subsequence(单调队列)
- Origin图中插入另一张jpg图
- slf4j 和 log4j合用的(Maven)配置
- 解析xml文件