最小割小记

这篇博客深入探讨了最小割问题,包括最小割的定义、求解方法以及多种题型的应用,如最下生成树、点的分割、最小点割集、最小割树、最大权闭合子图和点集划分等。通过实例解析和变形问题处理技巧,如黑白染色和翻转源汇,帮助理解最小割在解决图论问题中的核心作用。
摘要由CSDN通过智能技术生成

参考博客:最小割浅谈

关于最小割

  1. 常用描述
    表述一:删去若干条边使得源点到汇点不连通,求删边的权值和的最小可能值。
    表述二:将点集分为 ( S , T ) (S,T) (S,T),记所有从 S S S中出发到 T T T中的边的权值和为 c ( S , T ) c(S,T) c(S,T),求 c ( S , T ) c(S,T) c(S,T)的最小值。

  2. 求最小割
    a. 以权值为容量,该网络最大流的值即为最小割的值
    b. 在残量网络中,从源点出发进行一次增广BFS,即得到一个分割。该分割是一个最小割。

题型1:对求最小割原理的理解

[AHOI2009]最小割

在这里插入图片描述
在这里插入图片描述
摘自此Blog

[SDOI2014]LIS

在这里插入图片描述
在这里插入图片描述
摘自此Blog

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define re register
#define maxn 1505
#define LL long long
#define inf 999999999
inline int max(int a,int b){
   return a>b?a:b;}
inline int min(int a,int b){
   return a<b?a:b;}
inline int read()
{
   
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct node{
   int a,b,c,rk;}g[maxn];
inline int cmp(node A,node B) {
   return A.c<B.c;}
struct E{
   int v,nxt,w,f;}e[maxn*maxn];
int n,num=1,S,T,Test;
int ans[maxn],cnt,id[maxn],vis[maxn];
int d[maxn],dp[maxn],head[maxn],cur[maxn],in[maxn],out[maxn];
inline void add(int x,int y,int z) {
   e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=z;}
inline void C(int x,int y,int z) {
   add(x,y,z),add(y,x,0);}
inline int check(int s,int t)
{
   
    std::queue<int> q;
    memset(vis,0,sizeof(vis));
    q.push(s);vis[s]=1;
    while(!q.empty())
    {
   
        int k=q.front();q.pop();
        if(k==t) return 1;
        for(re int i=head[k];i;i=e[i].nxt)
        if(!vis[e[i].v]&&e[i].w>e[i].f) q.push(e[i].v),vis[e[i].v]=1;
    }
    return 0;
}
inline int BFS(int s,int t)
{
   
    std::queue<int> q;
    memcpy(cur,head,sizeof(head));
    memset(d,0,sizeof(d));
    d[s]=1,q.push(s);
    while(!q.empty())
    {
   
        int k=q.front();q.pop();
        for(re int i=head[k];i;i=e[i].nxt)
        if(!d[e[i].v]&&e[i].w>e[i].f) 
        {
   
            d[e[i].v]=d[k]+1;
            if(e[i].v==t) return 1;
            q.push(e[i].v);
        }
    }
    return d[t];
}
int dfs(int x,int now,int t)
{
   
    if(x==t||!now) return now;
    int flow=0,ff;
    for(re int& i=cur[x];i;i=e[i].nxt)
    if(d[e[i].v]==d[x]+1)
    {
   
        ff=dfs(e[i].v,min(now,e[i].w-e[i].f),t);
        if(ff<=0) continue;
        now-=ff,flow+=ff;
        e[i].f+=ff,e[i^1].f-=ff;
        if(!now) break;
    }
    return flow;
}
int main()
{
   
    Test=read();
    while(Test--)
    {
   
        n=read();cnt=0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Protobuf是一种高效的序列化协议,可以用于数据交换和数据存储。它的主要优势是大小小,速度快,可扩展性强。下面是使用Protobuf的一些小记: 1. 定义消息格式 首先,需要定义消息格式,以便Protobuf可以将数据序列化和反序列化。消息格式定义在.proto文件中,使用protobuf语言编写。例如,下面是一个简单的消息格式定义: ``` syntax = "proto3"; message Person { string name = 1; int32 age = 2; } ``` 这个消息格式定义了一个名为Person的消息,包含两个字段:name和age。 2. 生成代码 一旦消息格式定义好,就可以使用Protobuf编译器生成代码。编译器将根据消息格式定义生成相应的代码,包括消息类、序列化和反序列化方法等。可以使用以下命令生成代码: ``` protoc --java_out=. message.proto ``` 这将生成一个名为message.pb.java的Java类,该类包含Person消息的定义以及相关方法。 3. 序列化和反序列化 一旦生成了代码,就可以使用Protobuf序列化和反序列化数据。例如,下面是一个示例代码,将一个Person对象序列化为字节数组,并将其反序列化为另一个Person对象: ``` Person person = Person.newBuilder() .setName("Alice") .setAge(25) .build(); byte[] bytes = person.toByteArray(); Person deserializedPerson = Person.parseFrom(bytes); ``` 这个示例代码创建了一个Person对象,将其序列化为字节数组,然后将其反序列化为另一个Person对象。在这个过程中,Protobuf使用生成的代码执行序列化和反序列化操作。 以上是使用Protobuf的一些基本步骤和注意事项,希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值