题意

有$n​$个小朋友,给每个人分$1~m​$个糖果,有k个限制 限制形如$(x,y,z)​$ 表示第$x​$个人分到的糖数减去第$y​$个人分到的糖数不大于$z​$,给第$i​$个人$j​$颗糖获得的满意度为$w_{i,j}​$,问总满意度最大值


点$(i,j)$表示第$i$个人分$j$个糖,当这个点属于$s$集合成立,因为是求满意度最大值,所以负权建边,同时加上个最大值$Max$使得满足最大流模板,假设不考虑限制,对于每一个$i$,连边$(i,j)\rightarrow (i,j+1),j\in[1,m)$,边权为$Max-w_i,j$,$s\rightarrow(i,1)$,那么此时的最小割便是能得到最大满意度

对于每个限制,当$x$选了$i$个糖,那么$y$至少要选$i-z$个糖,连边$(x,i)\rightarrow s, i \in [1,m] \land i - z < 1$,或$(x,i)\rightarrow (y,i-z), i \land [1,m] \land 1 \le i - z \le m$ ,或$(x,i)\rightarrow t, i \in [1,m] \land i - z > m$ ,边权为$inf$,这样,当不满足限制的割边发生时,得到的最小割会大于$inf$

关于限制的建边的详细题解:http://blog.csdn.net/wing_wuchen/article/details/77407413

答案为$Max*n-mincut$

代码

#include <bits/stdc++.h>
#define MAXN 300005
#define MAXM 50000005
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
struct Edge {
int to, nxt, c;
}edge[MAXM];
int head[MAXN], cnt = 0;
int d[MAXN], cur[MAXN], pre[MAXN], gap[MAXN];
int source, sink, limit;
void init() {
memset(head, -1, sizeof(head));
cnt = 0;
}
inline void add_edge(int u, int v, int c) {
edge[cnt].to = v;
edge[cnt].nxt = head[u];
edge[cnt].c = c;
head[u] = cnt++;
} inline void add(int u, int v, int c) {
add_edge(u, v, c); add_edge(v, u, 0);
} void rev_bfs() {
memset(gap, 0, sizeof(gap));
memset(d, -1, sizeof(d));
d[sink] = 0;
gap[0] = 1;
queue<int> que;
que.push(sink);
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(~d[v])continue;
d[v] = d[u] + 1;
gap[d[v]]++;
que.push(v);
}
}
}
int isap() {
memcpy(cur, head, sizeof(cur));
rev_bfs();
int flow = 0, i;
int u = source;
pre[source] = source;
while(d[sink] < limit) {
if(u == sink) {
int f = inf, neck;
for(i = source; i != sink; i = edge[cur[i]].to) {
if(f > edge[cur[i]].c) {
f = edge[cur[i]].c;
neck = i;
}
}
for(i = source; i != sink; i = edge[cur[i]].to) {
edge[cur[i]].c -= f;
edge[cur[i] ^ 1].c += f;
}
flow += f;
u = neck;
}
for(i = cur[u]; ~i; i = edge[i].nxt) {
if(d[edge[i].to] + 1 == d[u] && edge[i].c) break;
}
if(~i) {
cur[u] = i;
pre[edge[i].to] = u;
u = edge[i].to;
}else {
if((--gap[d[u]]) == 0) break;
int mind = limit;
for(int i = head[u]; ~i; i = edge[i].nxt) {
if(edge[i].c && mind > d[edge[i].to]) {
cur[u] = i;
mind = d[edge[i].to];
}
}
d[u] = mind + 1;
gap[d[u]]++;
u = pre[u];
}
}
return flow;
}
int t, n, m, k, w[100][100], x, y, z;
int get(int x, int y) {return (x - 1) * m + y;}
int main() {
scanf("%d", &t);
while(t--) {
init();
scanf("%d%d%d", &n, &m, &k);
source = 0; sink = n * m + 1; limit = sink + 1;
for(int i = 1; i <= n; ++i) {
add(source, get(i, 1), inf);
for(int j = 1; j <= m; ++j) {
scanf("%d", &w[i][j]);
if(j < m) add(get(i, j), get(i, j + 1), 1000 - w[i][j]);
else add(get(i, j), sink, 1000 - w[i][j]);
}
}
for(int i = 1; i <= k; ++i) {
scanf("%d%d%d", &x, &y, &z);
for(int j = 1; j <= m; ++j) {
if(j - z < 1) add(get(x, j), source, inf);
else if(j - z <= m) add(get(x, j), get(y, j - z), inf);
else add(get(x, j), sink, inf);
}
}
int ans = isap();
if(ans >= inf) printf("-1\n"); else printf("%d\n", 1000 * n - ans);
}
return 0;
}

【HDU 6126】Give out candies 最小割的更多相关文章

  1. HDU 6126.Give out candies 最小割

    Give out candies Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Other ...

  2. hdu 6126 Give out candies

    hdu 6126 Give out candies(最小割) 题意: 有\(n\)个小朋友,标号为\(1\)到\(n\),你要给每个小朋友至少\(1\)个且至多\(m\)个的糖果.小朋友们共提出\(k ...

  3. HDU 4289:Control(最小割)

    http://acm.hdu.edu.cn/showproblem.php?pid=4289 题意:有n个城市,m条无向边,小偷要从s点开始逃到d点,在每个城市安放监控的花费是sa[i],问最小花费可 ...

  4. HDU 3452 Bonsai(网络流之最小割)

    题目地址:HDU 3452 最小割水题. 源点为根节点.再另设一汇点,汇点与叶子连边. 对叶子结点的推断是看度数是否为1. 代码例如以下: #include <iostream> #inc ...

  5. HDU 5889 Barricade 【BFS+最小割 网络流】(2016 ACM/ICPC Asia Regional Qingdao Online)

    Barricade Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  6. HDU 3526 Computer Assembling(最小割)

    http://acm.hdu.edu.cn/showproblem.php?pid=3526 题意:有个屌丝要配置电脑,现在有n个配件需要购买,有两家公司出售这n个配件,还有m个条件是如果配件x和配件 ...

  7. HDU 6214 Smallest Minimum Cut 最小割,权值编码

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6214 题意:求边数最小的割. 解法: 建边的时候每条边权 w = w * (E + 1) + 1; 这 ...

  8. HDU 3251 Being a Hero(最小割+输出割边)

    Problem DescriptionYou are the hero who saved your country. As promised, the king will give you some ...

  9. HDU 3691 Nubulsa Expo(全局最小割)

    Problem DescriptionYou may not hear about Nubulsa, an island country on the Pacific Ocean. Nubulsa i ...

随机推荐

  1. UNP学习笔记(第六章 I/O复用)

    I/O模型 首先我们将查看UNIX下可用的5种I/O模型的基本区别: 1.阻塞式I/O 2.非阻塞式I/O 3.I/O复用(select和poll) 4.信号驱动式I/O(SIGIO) 5.异步I/O ...

  2. 对于Json和对象转换的学习

    学习这个的用处有非常多的:        在传输数据过程中比較查看数据比較清晰,代码也较清晰.也能够避免split函数带来的隐藏bug 当然也有不足:        准备工具较繁琐,须要准备对象(当然 ...

  3. 强制重启Linux系统的几种方法

    实际生产环境中某些情况下 Linux 服务器系统在出现致命错误需要远程进行重启,通过常规的 reboot.init 6 等方法无法正常重启(例如重启时卡在驱动程序里等情况),这时就需要通过下面介绍的几 ...

  4. linq小实例

    var cus = from u in context.IPPhoneInfo join r in context.Organization on u.OrgStructure equals r.Mi ...

  5. Redis系列-存储篇list主要操作函数小结(转)

    在总结list之前,先要弄明白几个跟list相关的概念: 列表:一个从左到右的队列,个人理解更类似于一个栈,常规模式下,先进列表的元素,后出. 表头元素:列表最左端第一个元素. 表尾元素:列表最右端的 ...

  6. mBot试用体验

    [Arduino话题] [mBot试用体验]1.mBot开箱体验(部分资料合集)http://bbs.elecfans.com/forum.php?mod=viewthread&tid=532 ...

  7. HDFS源码分析心跳汇报之数据块增量汇报

    在<HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程>一文中,我们详细了解了数据节点DataNode周期性发送心跳给名字节点NameNode的BPServiceAct ...

  8. linux SPI驱动——spidev之driver(六)

    一: spidev_init注册spidev 1: static int __init spidev_init(void) 2: { 3: int status; 4:   5: /* Claim o ...

  9. jquery单选框radio绑定click事件实现方法

    本文实例讲述了jquery单选框radio绑定click事件实现方法.分享给大家供大家参考. 具体实现方法如下: 复制代码代码如下: <html><head><title ...

  10. erlang的随机数 及 random:uniform()函数

    每次调用会更新进程字典里的random_seed变量,这样在同一个进程内每次调用random:uniform()时,随机数种子都不同,所以生成的随机数都不一样(调用完random:uniform()后 ...