zoukankan      html  css  js  c++  java
  • 二元关系最小割

    处理一类问题:

    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
    */
  • 相关阅读:
    HDOJ 1015 Safecracker
    POJ3187 虽然超时了,但是还得纪念一下
    HDOJ 1248
    HDOJ 1161
    动态规划——砝码称重
    P01P02P03各种背包!!
    对基类与派生类对象和指针赋值的小结
    程序员技术练级攻略
    CodeForces 愚人节题目
    java入门
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10128052.html
Copyright © 2011-2022 走看看