二元关系最小割
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 */
以上是关于二元关系最小割的主要内容,如果未能解决你的问题,请参考以下文章
2019 Multi-University Training Contest 2 Harmonious Army(最小割)