zoukankan      html  css  js  c++  java
  • HDU 4888 Redraw Beautiful Drawings(网络流求矩阵的解)

    论文《为什么很多网络流问题总有整数解》http://diaorui.net/archives/189;

    参考:http://www.cnblogs.com/yuiffy/p/3929369.html

    题意:n*m的矩阵,给出每行的和以及每列的和,判断这样的矩阵是否存在,若存在,是否唯一;若唯一,输出解;

    思路:网络流,最大流+判环。网络流常用于求多项式整数解。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int inf=0x7fffffff;
    bool found,walked[500010];
    int t,nr,nc,k,sumr,sumc,ans;
    int r[500010],c[500010];
    int an[5005][5005];
    int head[500100],h[500010],g[500010]; //g[i]为层数为i的节点个数,h[i]为i点的层数
    int d[500010],augc;      //d记录当前弧,augc为增广路容量
    int cnt,st,ed,flow,n,m; //n个点m条边,flow为最大流
    struct node
    {
        int v,cap,next;
    };
    node e[500010];
    void add(int x,int y,int z)
    {
        e[cnt].v=y;
        e[cnt].cap=z;
        e[cnt].next=head[x];
        head[x]=cnt++;
    
        e[cnt].v=x;
        e[cnt].cap=0;
        e[cnt].next=head[y];
        head[y]=cnt++;
    }
    bool dfs(const int &x,const int &prex) //判环
    {
        int biu=-1;
        walked[x]=true;
        for(int i=head[x];i!=-1;i=e[i].next)
        {
            if(e[i].v==prex)
            {
                biu=i;continue;
            }
            if(e[i].cap>0)
            {
                if(walked[e[i].v]) return true;
                if(dfs(e[i].v,x)) return true;
            }
            if(biu==-1) head[x]=e[i].next; //走了这条边没发现环,删边
            else e[biu].next=e[i].next;
            biu=i;
        }
        walked[x]=false;
        return false;
    }
    void aug(const int &m) //dicnic
    {
        int i,mini,minh=n-1;
        int augco=augc;
        if(m==ed){ //当前点为汇点
            found=true;
            flow+=augc; //增加流量
            return;
        }
        for(i=d[m];i!=-1;i=e[i].next){ //寻找容许边
            if(e[i].cap&&h[e[i].v]+1==h[m]) //如果残留量大于0且是容许边
            {
                if(e[i].cap<augc) augc=e[i].cap;//如果残留量小于当前增广路流量,则更新增广路流量
                d[m]=i;   //把i定为当前弧
                aug(e[i].v);//递归
                if(h[st]>=n) return; //如果源点层数大于n,则返回
                if(found) break; //找到汇点,跳出
                augc=augco; //没找到就还原当前的流
            }
        }
        if(!found){
            for(i=head[m];i!=-1;i=e[i].next)
            {
                if(e[i].cap&&h[e[i].v]<minh){
                    minh=h[e[i].v];
                    mini=i;
                }
            }
            g[h[m]]--;
            if(!g[h[m]]) h[st]=n;
            h[m]=minh+1;
            d[m]=mini;
            g[h[m]]++;
        }else{ //修改残量
            e[i].cap-=augc; //正向减
            e[i^1].cap+=augc; //反向加
        }
    }
    void farm()
    {
        int i,j,x,y,z;
        memset(head,-1,sizeof(head));
        cnt=0;
        n=nc+nr+2;
        st=nc+nr+1;  //源点
        ed=nc+nr+2;  //汇点
        for(i=1;i<=nc;i++)
            add(st,i,c[i]);  //源点到行连边,容量为该行的和
        for(i=1;i<=nr;i++)
            add(nc+i,ed,r[i]);//列到汇点连边,容量为该列的和
        for(i=1;i<=nc;i++)
            for(j=1;j<=nr;j++)
            add(i,j+nc,k);    //行列间连边,容量为k
        memset(h,0,sizeof(h)); //层数,建分层图
        memset(g,0,sizeof(g));
        g[0]=n;
        flow=0;
        for(i=1;i<=n;i++)
            d[i]=head[i];   //当前弧初始化
        while(h[st]<n){
            augc=inf;      //初始时增广路容量无穷大
            found=false;
            aug(st);       //从源点开始找
        }
        if(flow!=sumr){ //达不到满流
            ans=0;
            return;
        }
        for(i=1;i<=nr;i++)
        {
            int k=1;
            for(j=head[nc+i];j!=-1;j=e[j].next)
            {
                if(e[j].v==ed) continue;
                an[i][k++]=e[j].cap;
                int thenext=e[j].next;
                while(thenext!=-1&&e[thenext].v==ed) thenext=e[thenext].next;
            }
        }
        memset(walked,false,sizeof(walked));
        for(i=nr;i>=1;i--)
        {
            if(dfs(i,-1))//将行数作为起始位置判环,若存在环,1~nr中必有点在环中
            {
                ans=2;
                return;
            }
        }
        ans=1;
    }
    int main()
    {
        int i,j,cas;
        while(scanf("%d%d%d",&nr,&nc,&k)!=EOF)
        {
            sumr=sumc=0;
            for(i=1;i<=nr;i++)
            {
                scanf("%d",&r[i]);
                sumr+=r[i];
            }
            for(i=1;i<=nc;i++)
            {
                scanf("%d",&c[i]);
                sumc+=c[i];
            }
            ans=0;
            if(sumr==sumc) farm();//和不同,则无解
            if(ans==0) printf("Impossible
    ");
            else if(ans!=1)
            {
                printf("Not Unique
    ");
            }
            else{
                printf("Unique
    ");
               for(i=1;i<=nr;i++)
               {
                   if(nc>=1) printf("%d",an[i][nc]);
                   for(j=nc-1;j>=1;j--)
                   {
                       printf(" %d",an[i][j]);
                   }printf("
    ");
               }
            }
        }
        return 0;
    }
  • 相关阅读:
    eclipse无法打断点,提示debug absent line number information
    jQueryValidator 验证非负数
    Oracle 11g中递归查询父类及子类集合
    修改上传功能时遇到的问题
    使用Tomcat页面乱码问题
    javaScript正则匹配汉字与特殊字符(项目中遇到关键字匹配的方法)
    Oracle 11g中字符串截取的实现
    软连接和硬连接区别 Alex
    Linux发行版的系统目录名称命名规则以及用途 Alex
    如何通过脚本实现显示版本号、CPU、硬盘和内存条大小 Alex
  • 原文地址:https://www.cnblogs.com/dashuzhilin/p/4643461.html
Copyright © 2011-2022 走看看