• 转自https://blog.csdn.net/cyendra/article/details/8989842
  • 题意
    • 的最小值
  • 题解
    • 之所以能够用最大流解决这个问题,关键在于最大流可以求解下面这个函数的最小值:
    • 接下来就分析一下如何用最大流求解上面这个函数的极值。
      • 首先xi一共只有两种选择,那么最终可以按xi的取值将xi划分成两个集合
      • 如果xi在值为1的集合里,xj在值为0的集合里,那么就会产生一个代价cij
      • 如果xi选择0就会产生一个bi的代价
      • 如果xi选择1就会产生一个ai的代价。
      • 于是构造一个源点S,汇点T做最小割,不妨假设做完最小割之后值为1的xi的集合是和S相连的部分,值为0的xi的集合是和T相连的部分。
    •  由于表达式中有三项,我们用三种割边来分别描述这三项的值。
      • 一种是xi选择了1,这样就不能选择0,需要把xi-T这条边割掉,由于xi选择1会产生ai的代价,那么就把这条边的容量设为ai
      • 另一种是xi选择了0,这样就不能选择1,需要把S-xi这条边割掉,由于xi选择0会产生bi的代价,那么就把这条边的容量设为bi
      • 最后一种是xi选择了1,xj选择了0,这样xi和xj不能在同一个集合中,需要把xi-xj这条边割掉,由于xi选择1,xj选择0产生cij的代价,那么就把这条边的容量设为cij。
    •  这样对建好的图做最小割就可以得到上面哪个函数的最小值。 
    • 接着我们分析这个题目如何转化成上面这种模型。首先我们将D的表达式赤裸裸地写出来:

       

    • 这种形式必然不能看出来和上面那个表达式有什么关系,于是我们继续将其化简:式子中间写错了

       

    • 如果令f等于最后一行括号里的内容
      • 如果ai选择0会产生sum{bij}(1<=j<=N)的代价
      • 如果ai选择1会产生ci的代价
      • 如果ai选择1且aj选择0就会产生bij的代价。这样就完全转化成了上面的模型
  • 代码
      • #include <iostream>
        #include <cstdio>
        #include <cstring>
        #include <cmath>
        #include <algorithm>
        #include <vector>
        #include <queue>
        #include <stack>
        #include 
        <map>
        #include <set>
         
        using namespace std;
         
        const int maxn=2222;
        const int maxm=2222222;
        const int INF=1e9;
         
        struct Edge{
            int from,to,cap,flow;
        };
         
        struct Dinic{
            int n,m,s,t;
            vector<Edge>edges;
            vector<int>G[maxn];
            bool vis[maxn];
            int d[maxn];
            int cur[maxn];
         
            void init(int n,int s,int t){
                this->n=n;
                this->s=s;
                this->t=t;
                for (int i=0;i<n;i++) G[i].clear();
                edges.clear();
                m=0;
            }
         
            void addedge(int from,int to,int cap){
                edges.push_back((Edge){from,to,cap,0});
                edges.push_back((Edge){to,from,0,0});
                m=edges.size();
                G[from].push_back(m-2);
                G[to].push_back(m-1);
            }
         
            bool BFS(){
                memset(vis,0,sizeof(vis));
                queue<int>que;
                que.push(s);
                d[s]=0;
                vis[s]=true;
                while (!que.empty()){
                    int x=que.front();que.pop();
                    for (int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if (!vis[e.to]&&e.cap>e.flow){
                            vis[e.to]=true;
                            d[e.to]=d[x]+1;
                            que.push(e.to);
                        }
                    }
                }
                return vis[t];
            }
         
            int DFS(int x,int a){
                if (x==t||a==0) return a;
                int flow=0,f;
                for (int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if (d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
                        e.flow+=f;
                        edges[G[x][i]^1].flow-=f;
                        flow+=f;
                        a-=f;
                        if (a==0) break;
                    }
                }
                return flow;
            }
         
            long long Maxflow(int s,int t){
                this->s=s;
                this->t=t;
                long long flow=0;
                while (BFS()){
                    memset(cur,0,sizeof(cur));
                    flow+=DFS(s,INF);
                }
                return flow;
            }
         
        }solver;
         
        int b[maxn][maxn];
        int c[maxn];
         
        int main()
        {
            int T,n,s,t,a,x;
            long long sum;
            scanf("%d",&T);
            while (T--)
            {
                scanf("%d",&n);
                s=0;
                t=n+1;
                solver.init(n+2,s,t);
                sum=0;
                for (int i=1;i<=n;i++)
                {
                    a=0;
                    for (int j=1;j<=n;j++)
                    {
                        scanf("%d",&x);
                        a+=x;
                        solver.addedge(i,j,x);
                    }
                    sum+=a;
                    solver.addedge(s,i,a);
                }
                for (int i=1;i<=n;i++)
                {
                    scanf("%d",&x);
                    solver.addedge(i,t,x);
                }
                printf("%I64d\n",sum-solver.Maxflow(s,t));
            }
            return 0;
        }

发表评论

邮箱地址不会被公开。 必填项已用*标注