zoukankan      html  css  js  c++  java
  • HDU 4307 Contest 1

    http://www.cnblogs.com/staginner/archive/2012/08/13/2636826.html

    自己看过后两周吧,重新写了一遍。很受启发的。对于0、1,可以使用最小割的思想来做,以前有听说过0、1规划的问题,估计就是这样的了。对这个题目使用最小割 ,是一个非常巧妙的思想。

    我把别人的题解复制过来吧。

    从本质上讲,之所以能够用最大流解决这个问题,关键在于最大流可以求解下面这个函数的最小值:

        

        接下来就分析一下如何用最大流求解上面这个函数的极值。

        首先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 <algorithm>
    #define LL __int64
    using namespace std;
    
    const int MAXN=1050;
    const int MAXM=2100000;
    const LL INF=0x7fffffff;
    
    struct Node
    {
        int from,to,next;
        LL cap;
    }edge[MAXM];
    int tol;
    int dep[MAXN];
    int head[MAXN];
    
    int n;
    void init()
    {
        tol=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int u,int v,LL w)
    {
        edge[tol].from=u;
        edge[tol].to=v; edge[tol].cap=w;  edge[tol].next=head[u];
        head[u]=tol++;
        edge[tol].from=v;
        edge[tol].to=u;
        edge[tol].cap=0;
        edge[tol].next=head[v];
        head[v]=tol++;
    }
    
    int BFS(int start,int end)
    {
        int que[MAXN];
        int front,rear; front=rear=0;
        memset(dep,-1,sizeof(dep));
        que[rear++]=start;
        dep[start]=0;
        while(front!=rear)
        {
            int u=que[front++];
            if(front==MAXN)front=0;
            for(int i= head[u];i!=-1; i=edge[i].next)
            {
                int v=edge[i].to;
                if(edge[i].cap>0&& dep[v]==-1)
                {
                    dep[v]=dep[u]+1;
                    que[rear++]=v;
                    if(rear>=MAXN) rear=0;
                    if(v==end)return 1;
                }
            }
        }
        return 0;
    }
    LL dinic(int start,int end)
    {
        LL res=0;
        int top;
        int stack[MAXN];
        int cur[MAXN];
        while(BFS(start,end))
        {
            memcpy(cur,head, sizeof(head));
            int u=start;
            top=0;
            while(1)
            {
                if(u==end)  
                {
                    LL min=INF;
                    int loc;
                   for(int i=0;i<top;i++)
    
                      if(min>edge[stack[i]].cap)
                      {
                          min=edge[stack[i]].cap;
                          loc=i;
                      }
                    for(int i=0;i<top;i++){
                        edge[stack[i]].cap-=min;
                        edge[stack[i]^1].cap+=min;
                    }
                    res+=min;         
                    top=loc;               
                    u=edge[stack[top]].from;
                }
                for(int i=cur[u]; i!=-1; cur[u]=i=edge[i].next)      
                  if(edge[i].cap!=0 && dep[u]+1==dep[edge[i].to])
                     break;
                if(cur[u]!=-1)
                {
                    stack [top++]= cur[u];
                    u=edge[cur[u]].to;
                }
                else
                {
                    if(top==0) break;
                    dep[u]=-1;
                    u= edge[stack[--top]].from;  
                }
            }
        }
        return res;
    }
    
    
    int main(){
    	int T,n,x,start=0,ent=1049;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d",&n);
    		init();
    		LL sum=0,a=0;
    		for(int i=1;i<=n;i++){
    			a=0;
    			for(int j=1;j<=n;j++){
    				scanf("%d",&x);
    				a+=x;
    				addedge(i,j,(LL)x);
    			}
    			addedge(start,i,a);
    			sum+=a;
    		}
    		for(int i=1;i<=n;i++){
    			scanf("%d",&x);
    			addedge(i,ent,(LL)x);
    		}
    		printf("%I64d
    ",sum-dinic(start,ent));
    	}
    }
    

      

  • 相关阅读:
    HDU1720 A+B Coming
    HDU1390 ZOJ1383 Binary Numbers
    HDU1390 ZOJ1383 Binary Numbers
    HDU2504 又见GCD
    HDU2504 又见GCD
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1020 ZOJ2478 Encoding
    HDU1020 ZOJ2478 Encoding
    HDU2097 Sky数
  • 原文地址:https://www.cnblogs.com/jie-dcai/p/4086407.html
Copyright © 2011-2022 走看看