zoukankan      html  css  js  c++  java
  • hdu 4862KM&最小费用最大流

    /*最小K路径覆盖的模型,用费用流或者KM算法解决,
    构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,
    流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,
    费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,
    费用为从x格子到y格子的花费能量减去得到的能量,流量1,
    再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,
    费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流,
    如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量
    因为要求最小路径覆盖,n*m-maxflow<=k ,所以maxflow+k>=n*m,如果是满流的话就存在最小费用最大流可求出,否则*/
    #include<stdio.h>
    #include<math.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    #define inf 0x3fffffff
    #define N  500
    struct node
    {
        int u,v,w,f,next;
    } bian[N*N*10];
    char ss[N][N];
    int ma[N][N];
    int manha(int i,int j,int ii,int jj)
    {
        if(ma[i][j]==ma[ii][jj])
            return   ii-i+jj-j-1-ma[i][j];
        return   ii-i+jj-j-1;
    }
    /*模板*/
    int dis[N],pre[N],head[N],visit[N],yong,maxflow;
    void init()
    {
        memset(head,-1,sizeof(head));
        yong=0;
    }
    void build(int u,int v,int w,int f)
    {
        bian[yong].u=u;
        bian[yong].v=v;
        bian[yong].w=w;
        bian[yong].f=f;
        bian[yong].next=head[u];
        head[u]=yong++;
    }
    void adde(int u,int v,int w,int f)
    {
        build(u,v,w,f);
        build(v,u,-w,0);
    }
    int min_cost(int s,int t)
    {
        int sum=0;
        while(1)
        {
            memset(visit,0,sizeof(visit));
            memset(pre,-1,sizeof(pre));
            for(int i=0; i<=t; i++) //注意是从0开始而不是从s开始
                dis[i]=inf;
            queue<int>q;
            visit[s]=1;//必须是s
            q.push(s);
            dis[s]=0;
            while(!q.empty ())
            {
                int u=q.front ();
                for(int index=head[u]; index!=-1; index=bian[index].next)
                {
                    int v=bian[index].v;
                    if(bian[index].f&&dis[v]>dis[u]+bian[index].w)
                    {
                        dis[v]=dis[u]+bian[index].w;
                        pre[v]=index;
                        if(!visit[v])
                        {
                            visit[v]=1;
                            q.push (v);
                        }
                    }
                }
                q.pop();
                visit[u]=0;//是u
            }
            int i;
            if(dis[t]==inf)
                break;
            int minn=inf;
            i=pre[t];
            while(i!=-1)
            {
                if(minn>bian[i].f)
                    minn=bian[i].f;
                i=pre[bian[i].u];
            }
            maxflow+=minn;
            sum=sum+minn*dis[t];
            i=pre[t];
            while(i!=-1)
            {
                bian[i].f-=minn;
                bian[i^1].f+=minn;
                i=pre[bian[i].u];
            }
        }
        return sum;
    }
    /*最小费用最大流*/
    int main()
    {
        int n,m,i,j,k,s,t,T,kk,r,l,su,index=0;
        scanf("%d",&T);
        while(T--)
        {
            init();
            scanf("%d%d%d",&n,&m,&k);
            for(i=1; i<=n; i++)
                scanf("%s",ss[i]+1);
            for(i=1; i<=n; i++)
                for(j=1; j<=m; j++)
                    ma[i][j]=ss[i][j]-'0';
            s=0;
            kk=2*n*m+1;
            t=kk+1;
            for(i=1; i<=n*m; i++)
                adde(s,i,0,1);
            adde(s,kk,0,k);
            for(i=n*m+1; i<=n*m*2; i++)
            {
                adde(kk,i,0,1);
                adde(i,t,0,1);
            }
            for(i=1; i<=n; i++)
                for(j=1; j<=m; j++)
                {
                    for(r=j+1; r<=m; r++)
                    {
                        int w=manha(i,j,i,r);
                        adde((i-1)*m+j,(i-1)*m+r+n*m,w,1);
                    }
                    for(r=i+1; r<=n; r++)
                    {
                        int w=manha(i,j,r,j);
                        adde((i-1)*m+j,(r-1)*m+j+n*m,w,1);
                    }
                }
            maxflow=0;
            su=min_cost(s,t);
            printf("Case %d : ",++index);
            if(maxflow==n*m)
                printf("%d
    ",-su);
            else
                printf("%d
    ",-1);
        }
        return 0;
    }
    

  • 相关阅读:
    使用AsyncTask简单的文件遍历
    如何创建黑名单
    关于PopupMenu的用法
    联系人的搜索和添加
    php获取真实IP地址
    socket.io获取客户端的IP地址(修正官方1.0.4版本BUG)
    ubuntu下安装bind9
    install source nginx 1.6.0
    在Ubuntu下的samba实现
    买了新硬盘,给ESXI的虚拟机挂进真实硬盘。
  • 原文地址:https://www.cnblogs.com/thefirstfeeling/p/4410662.html
Copyright © 2011-2022 走看看