小\(M\)的作物(最小割)

做的第一道网络流,因为一个智障错误调了好久嘤嘤嘤

题目描述

小\(M\)在\(MC\)里开辟了两块巨大的耕地\(A\)和\(B\)(你可以认为容量是无穷),现在,小\(P\)有\(n\)中作物的种子,每种作物的种子有\(1\)个(就是可以种一棵作物)(用\(1...n\)编号)。

现在,第\(i\)种作物种植在\(A\)中种植可以获得\(ai\)的收益,在\(B\)中种植可以获得\(bi\)的收益,而且,现在还有这么一种神奇的现象,就是某些作物共同种在一块耕地中可以获得额外的收益,小\(M\)找到了规则中共有\(m\)种作物组合,第\(i\)个组合中的作物共同种在\(A\)中可以获得\(c1i\)的额外收益,共同总在\(B\)中可以获得\(c2i\)的额外收益。

小\(M\)很快的算出了种植的最大收益,但是他想要考考你,你能回答他这个问题么?

输入输出格式

输入格式:

第一行包括一个整数\(n\)

第二行包括\(n\)个整数,表示\(ai\)第三行包括\(n\)个整数,表示\(bi\)第四行包括一个整数\(m\)接下来\(m\)行,

对于接下来的第\(i\)行:第一个整数\(ki\),表示第\(i\)个作物组合中共有\(ki\)种作物,

接下来两个整数\(c1i\),\(c2i\),接下来\(ki\)个整数,表示该组合中的作物编号。

输出格式:

只有一行,包括一个整数,表示最大收益

输入输出样例

输入样例:

3
4 2 1
2 3 2
1
2 3 2 1 2

输出样例:

11

\(Solution\)

一开始看这个题我毫无头绪。这是网络流?不会建图啊。

分析一下题目,有\(n\)个点,放在\(A\)里面有\(ai\)的收益,放在\(B\)里面有\(bi\)的收益。相当于从这个点到\(A\)有\(ai\)的流,到\(B\)有\(bi\)的流。于是求最大收益就是求总收益减去最小割,因为一个点只能放在一个集合里。

那组合怎么办?

显然组合内部的点要么都在一个集合里,要么这个点就没有贡献。也就是说,组合内部的点永远不能断开。我们建一个虚点,分别连接组合内部的点,边权是\(INF\),这样就永远不会断开。因为每个组合有三种情况:对\(A\)有贡献,对\(B\)有贡献,都没贡献,所以只建一个虚点是不够的,于是建两个。

第一个链接\(A\)点,边权是\(c1\),然后和组合内部的点相连。第二个有组合内部的点连过来,然后指向\(B\)点,边权是\(c2\)。

这样图就建好了,然后跑最小割就行了。

关于最小割

首先,最大流等于最小割,证明脑补。

也就是说,求最小割就是求最大流。

思想比较简单,就是每次找一条还能增加流量的路径,增加流量,直到没有路径可以增加流量。

每次\(bfs\)求最短的还有流量的路径,然后\(dfs\)求出能增加的流量,也就是这条路上残余流量最少的那条路的流量,答案加上这个数,顺便更新路径流量就好啦。

\(dinic\):每次\(bfs\)的时候记录每个点到源点的最短路径条数,\(dfs\)按照最短路增广。

详解见代码

#include<iostream>
#include<cstring>
#include <cstdio>
#include <queue>
using namespace std;
long long read(){
long long x = 0;int f = 0;char c = getchar();
while(c < '0' || c > '9') f |= c == '-',c = getchar();
while(c >= '0' && c <= '9') x = (x << 1) + ( x << 3) + ( c ^ 48), c = getchar();
return f ? -x: x;
} const int INF = 2147483647;
int n, m, a[1003], b[1003], ans, T, S;
struct szh{
int to, next, w;
}e[5000005];
int head[3003],cnt = 1;//1^1=0,2^1=3,4^1=5......
void add(int x,int y,int z){
e[++cnt].to = y,e[cnt].next = head[x],e[cnt].w = z,head[x] = cnt;
} int dis[3003], fir[3003];
bool bfs(){ //求是否有通路
memset(dis, 0, sizeof(dis)); //每次清零
queue<int> q;
q.push(S), dis[S] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
for (int i = head[u], v;v = e[i].to, i;i = e[i].next)
if(e[i].w > 0 && !dis[v]) dis[v] = dis[u] + 1, q.push(v);
//如果当前边可以走,并且没有被搜到过,也就是说当前是最短路
}
return dis[T]; //看是否能到汇点
} int dfs(int u, int flow){ //求通路最小流量
if(u == T || !flow) return flow; //若到汇点就返回
int sum = 0;
for (int &i = fir[u], v;v = e[i].to, i;i = e[i].next)
//取址是一个弧优化。因为每次增广,一个点可能被搜到多次,
//而一个弧被走两次没有意义,所以取址直接删掉这一条弧
if(e[i].w > 0 && dis[v] == dis[u] + 1){
//如果当前边有流量且是最短路,更新
int x = dfs(v, min(e[i].w, flow)); //x为当前通路的最小流量
e[i].w -= x,e[i^1].w += x,sum += x; //更新
if(!(flow -= x)) break; //如果不能再有更多的流量了,就退出
}
return sum;
} void dinic(){
while(bfs()){ //只要有通路,就可以进行增广
for(int i = 0;i <= T;++ i) fir[i] = head[i];
//因为后面会弧优化,所以另开一个数组代替
ans -= dfs(S, INF);
}
} int main(){
n = read();
for (int i = 1;i <= n;++ i) ans += a[i] = read();
for (int i = 1;i <= n;++ i) ans += b[i] = read();
m = read();
S = 0,T = (m+m+n+1);
for (int i = 1;i <= n;++ i)
add(S, i+m, a[i]),add(i+m, S, 0),add(i+m, T, b[i]),add(T, i+m, 0);
for (int i = 1;i <= m;++ i){
int k = read(),c1 = read(),c2 = read();
while(k --){
int x = read();
add(i, x+m, INF),add(x+m, i, 0); //建图
add(x+m, i+n+m, INF),add(i+m+n, x+m, 0);
}
add(S, i, c1),add(i, S, 0),add(i+n+m, T, c2),add(T, i+n+m, 0);
ans += (c1 + c2);
}
dinic();
printf("%d", ans);
return 0;
}

[网络流]小M的作物的更多相关文章

  1. P1361 小M的作物

    P1361 小M的作物 题目描述 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号). 现在,第 ...

  2. 洛谷 P1361 小M的作物 解题报告

    P1361 小M的作物 题目描述 小M在MC里开辟了两块巨大的耕地\(A\)和\(B\)(你可以认为容量是无穷),现在,小\(P\)有\(n\)中作物的种子,每种作物的种子有1个(就是可以种一棵作物) ...

  3. BZOJ 3438 小M的作物 & BZOJ 1877 [SDOI2009]晨跑

    我由衷地为我的朋友高兴.哈哈,yian,当你nick name破百上千时,再打“蒟蒻”就会被打的. 好的,说正事吧.请注意,这还是题解.但我发现,网络流实在是太套路了(怪不得这两年几乎销声匿迹).我们 ...

  4. 【BZOJ-3438】小M的作物 最小割 + 最大权闭合图

    3438: 小M的作物 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 825  Solved: 368[Submit][Status][Discuss ...

  5. BZOJ 3438: 小M的作物( 最小割 )

    orz出题人云神... 放上官方题解... 转成最小割然后建图跑最大流就行了... ---------------------------------------------------------- ...

  6. BZOJ_3438_小M的作物_最小割

    BZOJ_3438_小M的作物_最小割 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物) ...

  7. 【BZOJ3438】小M的作物 最小割

    [BZOJ3438]小M的作物 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物)(用1. ...

  8. luogu P1361 小M的作物

    题目链接 luogu P1361 小M的作物 题解 源汇点为A,B 向种子连边,容量为价值,每个种子能与A或B联通,考虑最小割 用建边的总流量减去最小割就是答案 相同利益的时候新建节点,由额外利益构成 ...

  9. 3438: 小M的作物[最小割]

    3438: 小M的作物 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1073  Solved: 465[Submit][Status][Discus ...

随机推荐

  1. Playfair加密

    前面讲的不管是单码加密还是多码加密都属于单图加密,什么是单图加密和多图加密呢,简单来说单图加密就是一个字母加密一个字母,而多图加密就是一个字符组加密一个字符组.比如双图加密就是两个字母加密两个字母,这 ...

  2. 华策光通信: LED可见光通信室内定位项目获最具投资价值奖

    3月21日上午,一场持续3个多小时的O2O领域的创业DemoShow在深圳科兴科学园会议中心激烈上演.来自华策光通信的基于LED可见光通信室内精准定位项目作为LED与室内定位领域的跨界融合项目经过精彩 ...

  3. 20135234mqy 实验二 Java面向对象程序设计

      北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计  班级:1352  姓名:mqy  学号:20135234 成绩:             指导教师: ...

  4. 07慕课网《进击Node.js基础(一)》HTTP小爬虫

    获取HTML页面 var http = require('http') var url='http://www.imooc.com/learn/348' http.get(url,function(r ...

  5. 《Spring2之站立会议5》

    <Spring2之站立会议5> 昨天,接着对主界面进行代码的编写,实现了界面的美化,从图片库中调了一些图片对其进行优化: 今天,向主界面中加入语音功能部分的代码: 遇到的问题:发现虽然是调 ...

  6. iOS App之间常用的五种通信方式及适用场景总结

    iOS系统是相对封闭的系统,App各自在各自的沙盒(sandbox)中运行,每个App都只能读取iPhone上iOS系统为该应用程序程序创建的文件夹AppData下的内容,不能随意跨越自己的沙盒去访问 ...

  7. 用css 修改 谷歌浏览器自带的 滚动条样式

    ::-webkit-scrollbar { width: 0.5rem;}/* Track */ ::-webkit-scrollbar-track { -webkit-box-shadow: ins ...

  8. PAT 1054 求平均值

    https://pintia.cn/problem-sets/994805260223102976/problems/994805272659214336 本题的基本要求非常简单:给定N个实数,计算它 ...

  9. 通过session 怎么防止表单的重复提交!

    1.在提交表单的时候使用隐藏域: String tokenValue=new Date().getTime(); <input type="hidden" name=&quo ...

  10. pycharm安装jpype报错及解决方法

    安装jpype时发生报错: 按照提示去装了Microsoft visual C++,结果重新安装还是报错,根据https://blog.csdn.net/qq_38934189/article/det ...