二者取其一(初遇)_网络流

二者取其一,就是一堆物品,放入两个集合内,放进不同的集合内就会有不同的收益(或代价),使其收益(代价)最大(最小)的一种问题

通常这类问题,使用最小割定理解决。

最小割,即割边集中权值之和最小的一个集合

比如这道题[SHOI2007]善意的投票

是一道这样类型的题。

我们将\(S\)点设为同意睡觉的超级源点\(T\)设为不同意睡觉的点,同以对好朋友之间连一条容量为1的无向边,这样建图。我们求得一个最小割,就是答案的解了

不过这里有一个与其他网络流不同的地方,就是朋友间为什么要建立无向边,而不是有向边呢?

我们如此思考,假设a,b不统一意见。有两种决策,

  • 让a同意b
  • 让b同意a

有两种情况,我们并不能准确确定割边在哪个地方,所以我们需要建出两种情况的边来。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cstring>
using std::queue;
using std::min;
const int maxn=11000;
int n,m;
struct node
{
    int p;
    long long f;
    int nxt;
};
int head[maxn],tail=-1;
int dis[maxn];
int cur[maxn];
node line[maxn<<5];
void add(int a,int b,long long c)
{
    line[++tail].p=b;
    line[tail].f=c;
    line[tail].nxt=head[a];
    head[a]=tail;
}
bool bfs(int s,int t)
{
    queue<int>q;
    memset(dis,0,sizeof(dis));
    dis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int pas=q.front();q.pop();
        for(int i=head[pas];i!=-1;i=line[i].nxt)
            if(!dis[line[i].p]&&line[i].f)
            {
                dis[line[i].p]=dis[pas]+1;
                q.push(line[i].p);
            }
    }
    return dis[t];
}
long long dfs(int now,int aim,long long flow)
{
    long long res=0,f;
    if(now==aim||!flow) return flow;
    for(int &i=cur[now];i!=-1;i=line[i].nxt)
        if(dis[line[i].p]==dis[now]+1&&(f=dfs(line[i].p,aim,min(flow,line[i].f))))
        {
            res+=f;
            flow-=f;
            line[i].f-=f;
            line[i^1].f+=f;
            if(!flow) break;
        }
    return res;
}
long long dinic(int s,int t)
{
    long long res=0;
    while(bfs(s,t))
    {
        for(int i=0;i<=n+1;i++)
            cur[i]=head[i];
        res+=dfs(s,t,0x7fffffff);
    }
    return res;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    int a,b,c,d;
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        if(a)
            add(0,i,1),add(i,0,0);
        else
            add(i,n+1,1),add(n+1,i,0);
        ans+=1;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b,1);
        add(b,a,1);
    }
    printf("%d",dinic(0,n+1));
}

原文地址:https://www.cnblogs.com/Lance1ot/p/9387604.html

时间: 2024-10-27 21:10:40

二者取其一(初遇)_网络流的相关文章

HLG 2163 方格取数 (最大网络流)

题目链接:  m=ProblemSet&a=showProblem&problem_id=2163">点击打开链接 Description : 给你一个n*n的格子的棋盘,每一个格子里面有一个非负数.如今从中取出若干个数,使得随意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻.而且取出的数的和最大. Input : 包含多个測试实例,每一个測试实例包含一个整数n 和n*n个非负数x(n<=20, 0 <= x <= 1000). Out

方格取数问题(网络流)

方格取数问题(luogu) Solution 可以利用网络流对“斥”的求解 先假设所有点都选,不选某些点可以使选择的方案合法,求出这些不选的点的价值总和的最小值 最小值联想到最小割 根据(横坐标+纵坐标)的奇偶性将图分成两部分 在不能同时选的点间连边(方向偶-奇),由于“割”时不能割掉点之间不能同时选的关系,所以它的流量应为正无穷 再从起点向偶部的每个点连一条流量为这个点的价值的边,从奇部的每个点向终点连一条流量为这个点的价值的边, 表示不选它失去的价值 跑最大流(即最小割) Code #inc

Codevs_1166_[NOIP2007]_矩阵取数游戏_(动态规划+高精度)

描述 http://codevs.cn/problem/1166/ 分析 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn=50; 8 9 struct Bign{ 10 int x[maxn],cnt; 11 int & operator []

【scrapy实践】_爬取安居客_广州_新楼盘数据

需求:爬取[安居客-广州-新楼盘]的数据,具体到每个楼盘的详情页的若干字段. 难点:楼盘类型各式各样:住宅 别墅 商住 商铺 写字楼,不同楼盘字段的名称不一样.然后同一种类型,比如住宅,又分为不同的情况,比如分为期房在售,现房在售,待售,尾盘.其他类型也有类似情况.所以字段不能设置固定住. 解决方案:目前想到的解决方案,第一种:scrapy中items.py中不设置字段,spider中爬的时候自动识别字段(也就是有啥字段就保留下来),然后返回字典存起来.第二种,不同字段的网页分别写规则单独抓取.

[bzoj1565][NOI2009]植物大战僵尸_网络流_拓扑排序

植物大战僵尸 bzoj1565 题目大意:给你一张网格图,上面种着一些植物.你从网格的最右侧开始进攻.每个植物可以对僵尸提供能量或者消耗僵尸的能量.每个植物可以保护一个特定网格内的植物,如果一个植物被保护,那么如果僵尸想吃掉该植物就必须先吃掉保护它的植物.问:僵尸最多能获得多少能量. 注释:1<=N(网格的宽)<=20,1<=M(网格的长)<=30,-20,000<=代价和收益<=20,000. 想法:前置题目([NOI2006]最大获利).这道题和最大获利比较相像,如

[LuoguP1264]K-联赛_网络流

K-联赛 题目链接:https://www.luogu.org/problem/P1264 数据范围:略. 题解: 首先,枚举所有球队是否作为答案是必须的. 因为发现$n$实在是特别小,很容易想到网络流. 至于怎么建图,非常常规. 把比赛和球队都抽象成点. 源点$S$向每种比赛练这种比赛次数大小的容量: 每个比赛向这两个球队连边权为$inf$的容量: 每个球队向汇点$T$连这个球队和枚举球队的比赛差. 原文地址:https://www.cnblogs.com/ShuraK/p/11679493.

[bzoj2229][Zjoi2011]最小割_网络流_最小割树

最小割 bzoj-2229 Zjoi-2011 题目大意:题目链接. 注释:略. 想法: 在这里给出最小割树的定义. 最小割树啊,就是这样一棵树.一个图的最小割树满足这棵树上任意两点之间的最小值就是原图中这两点之间的最小割. 这个性质显然是非常优秀的. 我们不妨这样假设,我么已经把最小割树求出来了,那么这个题就迎刃而解了. 我们可以直接枚举点对,然后暴力验证就可以直接枚举出所有的合法点对是吧. 那么问题来了,我们如何才能求出所有的合法的点对? 这就需要用到了最小割树的构建过程. 我们最小割树的构

[bzoj1733][Usaco2005 feb]Secret Milking Machine 神秘的挤奶机_网络流

[Usaco2005 feb]Secret Milking Machine 神秘的挤奶机 题目大意:约翰正在制造一台新型的挤奶机,但他不希望别人知道.他希望尽可能久地隐藏这个秘密.他把挤奶机藏在他的农场里,使它不被发现.在挤奶机制造的过程中,他需要去挤奶机所在的地方T(1≤T≤200)次.他的农场里有秘密的地道,但约翰只在返回的时候用它.农场被划分成N(2≤N≤200)块区域,用1到200标号.这些区域被P(1≤P≤40000)条道路连接,每条路有一个小于10^6的长度L.两块区域之间可能有多条

Vijos 1451 圆环取数 【区间DP】

背景 小K攒足了路费来到了教主所在的宫殿门前,但是当小K要进去的时候,却发现了要与教主守护者进行一个特殊的游戏,只有取到了最大值才能进去Orz教主-- 描述 守护者拿出被划分为n个格子的一个圆环,每个格子上都有一个正整数,并且定义两个格子的距离为两个格子之间的格子数的最小值.环的圆心处固定了一个指针,一开始指向了圆环上的某一个格子,你可以取下指针所指的那个格子里的数以及与这个格子距离不大于k的格子的数,取一个数的代价即这个数的值.指针是可以转动的,每次转动可以将指针由一个格子转向其相邻的格子,且