二元关系最小割

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二元关系最小割相关的知识,希望对你有一定的参考价值。

处理一类问题:

N个任务,M对二元组关系(x,y),求最小总花费,条件如下:
每个任务可以在机器A或机器B上完成,分别花费Ai、Bi。
若x,y同时在A上完成,花费C1(x,y)。
若x,y同时在B上完成,花费C2(x,y)。
若x在A、y在B上完成,花费C3(x,y)。
若x在B,y在A上完成,花费C4(x,y)。

大概这种。

 

建模方法:

技术分享图片

根据割集的定义列方程。

然后求解即可。

最后得到每条边的最终权值,由于每个这样的二元组都要最终做出选择。这样最后的最小割就包含了全局的所有的代价(就是加法交换律结合律就凑出来了)。

 

然后一些细节。

 

技术分享图片

 

其实二元关系并不太常用,

对于比较容易解出答案的、某两个取不取会对答案造成影响的,就可以考虑这样建图。

是最小割建图的一个思路。

 

例题:

[国家集训队]人员雇佣

最大化收益的最小割,那么就把收益都算上,再减去为了符合题意而做出的最小的代价

直接列出方程:

a+b=0

a+f+d=3E

b+e+c=3E

c+d=2E

由于对称,直接e=f=2E,c=d=E,a=b=0即可。

这个题的好处是方程非常固定而且好解。

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^‘0‘)
using namespace std;
typedef long long ll;
il void rd(ll &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch==-)&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=1005;
const int V=1005;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,m,s,t;
int cur[V];
struct node{
    int nxt,to;
    ll w;
}e[2*(N*N*2+N*2)];
int hd[V],cnt=1;
int uu;
void add(int x,int y,ll w){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    e[cnt].w=w;
    hd[x]=cnt;
    
    e[++cnt].nxt=hd[y];
    e[cnt].to=x;
    e[cnt].w=0;
    hd[y]=cnt;
}
int d[V];
ll dfs(int x,ll flow){
    if(x==t) return flow;
    ll res=flow;
    for(reg i=cur[x];i&&res;i=e[i].nxt,cur[x]=i){
        int y=e[i].to;
        if(d[y]==d[x]+1&&e[i].w){
            ll k=dfs(y,min(res,e[i].w));
            if(!k) d[y]=0;
            e[i].w-=k;
            e[i^1].w+=k;
            res-=k;
        }
    }
    return flow-res;
}
int q[V],l,r;
bool bfs(){
    memset(d,0,sizeof d);
    l=1,r=0;
    q[++r]=s;
    d[s]=1;
    while(l<=r){
        int x=q[l++];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(!d[y]&&e[i].w){
                d[y]=d[x]+1;
                q[++r]=y;
                if(y==t) return true;
            }
        }
    }
    return false;
}
ll E[N][N];
ll ans;
ll no[N];
ll a[N];
int main(){
    rd(n);
    s=0,t=n+1;
    for(reg i=1;i<=n;++i){
        rd(a[i]);
        add(i,t,a[i]);
    }
    for(reg i=1;i<=n;++i){
        for(reg j=1;j<=n;++j){
            rd(E[i][j]);
            ans+=E[i][j];
            if(E[i][j]&&i<j){
                add(i,j,(ll)2*E[i][j]);
                add(j,i,(ll)2*E[i][j]);
                no[i]+=E[i][j];
                no[j]+=E[i][j];
            }
        }
    }
    for(reg i=1;i<=n;++i){
        add(s,i,no[i]);
    }
    ll flow=0;
    ll lp=0,po=0;
    while(bfs()){
        for(reg i=0;i<=n+1;++i) cur[i]=hd[i];
        while(flow=dfs(s,inf)) 
        ans-=flow;    
    }
    printf("%lld ",ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2018/12/16 16:53:09
*/

 








以上是关于二元关系最小割的主要内容,如果未能解决你的问题,请参考以下文章

网络流常见建图套路总结(重制版)

HDU 3526 最小割

hdu3251 最小割

2019 Multi-University Training Contest 2 Harmonious Army(最小割)

最大流最小割定理

P2057 [SHOI2007] 善意的投票(最小割)