zoukankan      html  css  js  c++  java
  • POJ 2396 有源有汇有上下界可行流问题

    题意:给一个矩阵,给出每行每列之和,附加一些条件,如第i行第j列数必需大于(小于)多少。
    思路题解:矩阵模型,模拟网络流,行、列标号为结点,构图,附加s,t,s连行标(容量上下限每行之和(必需以这个
    值全部送过去),每个列标连向t(容量上下限每列之和)),其他每个行到列都有边(有限制的按限制
    来,无限制的自己添加)。由于s->网络->t,若有解,总流量f必为
    矩阵所有数之和,故添加边t-S,容量上下线为矩阵和sum,这样保证了每个点出入流相等,满足流量平衡,
    转化为无源无汇有上下线可行流问题,在建立超级源点汇点ss,tt,按无源无汇法做一遍ss->tt最大流,
    判断可行即可。可行输出方案。PS,若题目改为求有源有汇有限制最大流问题,可以在残量网络再走一次
    s->t(原图源汇)最大流(solo可行的后悔边啥~)
    此题,有源有汇有限制可行流问题,主要是建图,就是一个字烦!其一:0的时候要所有,行列为0要
    讨论,其二,>,<,=符号的判定,讨论下,其三,重边,这个不是链前星锁解决那个重边,而是重边
    是“且”的关系,如,先给上限,再来一边给下限!坑爹啊这是要!无法,hash判重吧,重了,再修改原来的
    边,要搞清楚反向边(建图时跑第一次(第一次判断有无解)前)流量始终为0(提供后悔的,和之后没有

    半毛钱关系)!至于算法,不再是问题,dinic跑的。


    #include<iostream>  //47ms,1A
    #include<cstdio>
    #include<queue>
    #include<vector>
    using namespace std;
    int n,m;const int inf=0x3f3f3f3f;
    int suminf[300];int sumouf[300];
    int e[20000][5]; int head[300];int level[300];int vis[300];
    int hash[250][300];int ans[250][300];
    int nume=0;
    bool bfs()          //dinic“d,bfs”,不用说了
    {
        for(int i=0;i<n+m+4;i++)
           level[i]=vis[i]=0;
        vis[n+m+2]=1;
        queue<int>q;q.push(n+m+2);
        while(!q.empty())
        {
            int cur=q.front();q.pop();
            for(int i=head[cur];i!=-1;i=e[i][1])
            {
                int v=e[i][0];
                if(!vis[v]&&e[i][2]>0)
                {
                    level[v]=level[cur]+1;
                    vis[v]=1;
                    if(v==m+n+3)return 1;
                    q.push(v);
                }
            }
        }
        return vis[n+m+3];
    }
    int dfs(int u,int minf)
    {
        if(u==n+m+3||minf==0){return minf;}
        int sumf=0,f;
        for(int i=head[u];i!=-1&&minf;i=e[i][1])
            {
                int v=e[i][0];
                if(level[v]==level[u]+1&&e[i][2]>0)
                {
                    f=dfs(v,minf<e[i][2]?minf:e[i][2]);
                   if(f==0)continue;
                    e[i][2]-=f;e[i^1][2]+=f;
                    minf-=f;sumf+=f;
                }
            }
            return sumf;
    }
    void dinic()
    {
        int sumflow=0;
        while(bfs())
        {
            sumflow+=dfs(n+m+2,inf);
        }
    }
    bool check()           //无源无汇的,出发点ss(超级源点)的边有一条不满流就无解,原因简单必需保证流量平衡(为之提供下限)
    {
        for(int i=head[n+m+2];i!=-1;i=e[i][1])
        {
            if(e[i][2]!=0)return 0;
        }
        return 1;
    }
    int main()
    {
        int N;
        scanf("%d",&N);
        while(N--)   //N组输入
        {
            scanf("
    %d%d",&n,&m);   //忽略空行
             nume=0;
             int sum=0,temp;
             bool mark=0;
           for(int i=0;i<=n+m+5;i++)
             {
                 head[i]=-1;
                 suminf[i]=sumouf[i]=0;
             }
             for(int i=0;i<=n;i++)
               for(int j=n+1;j<=n+m+1;j++)
                  ans[i][j]=hash[i][j]=0;
            for(int i=1;i<=n;i++)                  //有源有汇的源点s
            {
                scanf("%d",&temp);sum+=temp;
                e[nume][0]=i;e[nume][1]=head[0];head[0]=nume;
                e[nume][2]=0;e[nume][3]=temp;e[nume++][4]=temp;
                suminf[i]+=temp;sumouf[0]+=temp;
                e[nume][0]=0;e[nume][1]=head[i];head[i]=nume;
                e[nume++][2]=0;
            }
            for(int i=n+1;i<=m+n;i++)         //汇点t
            {
                scanf("%d",&temp);
                e[nume][0]=n+1+m;e[nume][1]=head[i];head[i]=nume;
                e[nume][2]=0;e[nume][3]=temp;e[nume++][4]=temp;
                suminf[n+m+1]+=temp;sumouf[i]+=temp;
                e[nume][0]=i;e[nume][1]=head[n+m+1];head[n+m+1]=nume;
                e[nume++][2]=0;
            }
                e[nume][0]=0;e[nume][1]=head[n+m+1];head[n+m+1]=nume;  //添加t->s
                e[nume][2]=0;e[nume][3]=sum;e[nume++][4]=sum;
                 suminf[0]+=sum;sumouf[n+m+1]+=sum;
                e[nume][0]=n+m+1;e[nume][1]=head[0];head[0]=nume;
                e[nume++][2]=0;
            int ca;scanf("%d",&ca); int row,col,lim;char cc;
             for(int i=0;i<ca;i++)                          //按条件建图
             {
                 scanf("%d%d %c %d",&row,&col,&cc,&lim);
                 if(col!=0&&row==0)
                 {
                     if(cc=='=')
                      for(int i=1;i<=n;i++)
                       {
                         if(hash[i][n+col])        //判重,下面一致
                         {
                             int pp;
                             for( pp=head[i];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(lim>e[pp][3])e[pp][3]=lim;
                             if(lim<e[pp][4])e[pp][4]=lim;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3];
                         }
                         else
                         {
                         e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume;
                         e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim;
    
                         suminf[n+col]+=lim; sumouf[i]+=lim;hash[i][n+col]=1;
                         e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume;
                         e[nume++][2]=0;
                         }
                       }
                     else if(cc=='>')
                     {
                         for(int i=1;i<=n;i++)
                       {
                           if(hash[i][n+col])
                         {    int pp;
                             for( pp=head[i];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(lim+1>e[pp][3])e[pp][3]=lim+1;
                             if(inf<e[pp][4])e[pp][4]=inf;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3];
                         }
                         else
                        {
    
                         e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume;
                         e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf;
                         suminf[n+col]+=lim+1; sumouf[i]+=lim+1;hash[i][n+col]=1;
                         e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume;
                         e[nume++][2]=0;
                        }
                       }
                     }
                     else if(cc=='<')
                     {
                         for(int i=1;i<=n;i++)
                        if(hash[i][n+col])
                         {  int pp;
                             for(pp=head[i];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(0>e[pp][3])e[pp][3]=0;
                             if(lim-1<e[pp][4])e[pp][4]=lim-1;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[i]+=e[pp][3];
                         }
                         else
                        {
                         e[nume][0]=n+col;e[nume][1]=head[i];head[i]=nume;
                         e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[i][n+col]=1;
                         //inf[n+rol]+=lim; sumouf[i]+=lim;
                         e[nume][0]=i;e[nume][1]=head[n+col];head[n+col]=nume;
                         e[nume++][2]=0;
                        }
                       }
    
                 }
                 else if(row!=0&&col==0)
                 {
                      if(cc=='>')
                     {
                         for(int i=n+1;i<=n+m;i++)
                       {   if(hash[row][i])
                         {   int pp;
                             for( pp=head[row];e[pp][0]!=i;pp=e[pp][1])
                             ;
                             suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(lim+1>e[pp][3])e[pp][3]=lim+1;
                             if(inf<e[pp][4])e[pp][4]=inf;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                         else
                           {
                         e[nume][0]=i;e[nume][1]=head[row];head[row]=nume;
                         e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf;
                         suminf[i]+=lim+1; sumouf[row]+=lim+1;hash[row][i]=1;
                         e[nume][0]=row;e[nume][1]=head[i];head[i]=nume;
                         e[nume++][2]=0;
                           }
                       }
                     }
                     else if(cc=='=')
                      for(int i=n+1;i<=n+m;i++)
                       {
                              if(hash[row][i])
                         {    int pp;
                             for(pp=head[row];e[pp][0]!=i;pp=e[pp][1])
                             ;
                             suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(lim>e[pp][3])e[pp][3]=lim;
                             if(lim<e[pp][4])e[pp][4]=lim;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                         else
                        {
    
                         e[nume][0]=i;e[nume][1]=head[row];head[row]=nume;
                         e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim;
                         suminf[i]+=lim; sumouf[row]+=lim;hash[row][i]=1;
                         e[nume][0]=row;e[nume][1]=head[i];head[i]=nume;
                         e[nume++][2]=0;
                        }
                       }
                      else if(cc=='<')
                      for(int i=n+1;i<=n+m;i++)
                       {
                            if(hash[row][i])
                         {   int pp;
                             for( pp=head[row];e[pp][0]!=i;pp=e[pp][1])
                             ;
                             suminf[i]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(0>e[pp][3])e[pp][3]=0;
                             if(lim-1<e[pp][4])e[pp][4]=lim-1;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[i]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                         else
                        {
                         e[nume][0]=i;e[nume][1]=head[row];head[row]=nume;
                         e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[row][i]=1;
                         //inf[i]+=lim; sumouf[row]+=lim;
                         e[nume][0]=row;e[nume][1]=head[i];head[i]=nume;
                         e[nume++][2]=0;
                        }
                       }
                 }
                 else if(row==0&&col==0)
                 {
                     if(cc=='=')
                      {
                        for(int i=1;i<=n;i++)
                         for(int j=n+1;j<=n+m;j++)
                         {
                            if(hash[i][j])
                         {   int pp;
                             for( pp=head[i];e[pp][0]!=j;pp=e[pp][1])
                             ;
                             suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(lim>e[pp][3])e[pp][3]=lim;
                             if(lim<e[pp][4])e[pp][4]=lim;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3];
                         }
                         else
                           {
                            e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
                            e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim;
                            suminf[j]+=lim; sumouf[i]+=lim;hash[i][j]=1;
                            e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
                            e[nume++][2]=0;
                          }
                         }
                      }
                    if(cc=='>')
                    {
                       for(int i=1;i<=n;i++)
                         for(int j=n+1;j<=n+m;j++)
                         {
                            if(hash[i][j])
                           {  int pp;
                             for( pp=head[i];e[pp][0]!=j;pp=e[pp][1])
                             ;
                             suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(lim+1>e[pp][3])e[pp][3]=lim+1;
                             if(inf<e[pp][4])e[pp][4]=inf;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3];
                          }
                         else
                            {
                            e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
                            e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf;
                            suminf[j]+=lim+1; sumouf[i]+=lim+1;hash[i][j]=1;
                            e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
                            e[nume++][2]=0;
                            }
                         }
                    }
                     if(cc=='<')
                       for(int i=1;i<=n;i++)
                         for(int j=n+1;j<=n+m;j++)
                         {
                       if(hash[i][j])
                         {    int pp;
                             for( pp=head[i];e[pp][0]!=j;pp=e[pp][1])
                             ;
                             suminf[j]-=e[pp][3]; sumouf[i]-=e[pp][3];
                             if(0>e[pp][3])e[pp][3]=0;
                             if(lim-1<e[pp][4])e[pp][4]=lim-1;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[j]+=e[pp][3]; sumouf[i]+=e[pp][3];
                         }
                         else
                            {
                            e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
                            e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[i][j]=1;
                            //inf[j]+=lim; sumouf[i]+=lim;
                            e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
                            e[nume++][2]=0;
                            }
                         }
                 }
                 else
                 {
                     if(cc=='=')
                   {
                        if(hash[row][n+col])
                         {    int pp;
                             for(pp=head[row];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(lim>e[pp][3])e[pp][3]=lim;
                             if(lim<e[pp][4])e[pp][4]=lim;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                       else
                         {
                    e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume;
                    e[nume][2]=0;e[nume][3]=lim;e[nume++][4]=lim;
                    suminf[col+n]+=lim; sumouf[row]+=lim;hash[row][col+n]=1;
                    e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume;
                    e[nume++][2]=0;
                        }
                   }
                   else if(cc=='>')
                   {
                        if(hash[row][n+col])
                         {   int pp;
                             for(pp=head[row];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(lim+1>e[pp][3])e[pp][3]=lim+1;
                             if(inf<e[pp][4])e[pp][4]=inf;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                         else
                            {
                    e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume;
                    e[nume][2]=inf-lim-1;e[nume][3]=lim+1;e[nume++][4]=inf;
                    suminf[col+n]+=lim+1; sumouf[row]+=lim+1;hash[row][col+n]=1;
                    e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume;
                    e[nume++][2]=0;
                            }
                   }
                   else if(cc=='<')
                   {
                        if(hash[row][n+col])
                         {   int pp;
                             for( pp=head[row];e[pp][0]!=n+col;pp=e[pp][1])
                             ;
                             suminf[n+col]-=e[pp][3]; sumouf[row]-=e[pp][3];
                             if(0>e[pp][3])e[pp][3]=0;
                             if(lim-1<e[pp][4])e[pp][4]=lim-1;
                             if(e[pp][3]>e[pp][4])mark=1;
                             e[pp][2]=e[pp][4]-e[pp][3];
                             suminf[n+col]+=e[pp][3]; sumouf[row]+=e[pp][3];
                         }
                         else
                        {
    
                       e[nume][0]=col+n;e[nume][1]=head[row];head[row]=nume;
                        e[nume][2]=lim-1;e[nume][3]=0;e[nume++][4]=lim-1;hash[row][col+n]=1;
                   // inf[col]+=lim; sumouf[row]+=lim;
                      e[nume][0]=row;e[nume][1]=head[col+n];head[col+n]=nume;
                        e[nume++][2]=0;
                        }
                   }
                 }
             }
               for(int i=1;i<=n;i++)    //有些边没有限制,不要忘记加边!!
                 for(int j=n+1;j<=n+m;j++)
                   if(!hash[i][j])
                   {
                       e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
                       e[nume][4]=inf;e[nume++][2]=inf;
                       e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
                       e[nume++][2]=0;
                   }
                                    //无源无汇添加ss,tt
               for(int i=0;i<=n+m+1;i++)
               {
                    e[nume][0]=i;e[nume][1]=head[n+m+2];head[n+m+2]=nume;
                    e[nume++][2]=suminf[i];
                    e[nume][0]=n+m+2;e[nume][1]=head[i];head[i]=nume;
                    e[nume++][2]=0;
    
                    e[nume][0]=n+m+3;e[nume][1]=head[i];head[i]=nume;
                    e[nume++][2]=sumouf[i];
                    e[nume][0]=i;e[nume][1]=head[n+m+3];head[n+m+3]=nume;
                    e[nume++][2]=0;
               }
               dinic();     //从ss->tt,判断有无解
              if(mark||!check())printf("IMPOSSIBLE
    ");
              else             //输出答案
              {
                  for(int i=1;i<=n;i++)
                    for(int j=head[i];j!=-1;j=e[j][1])
                      ans[i][e[j][0]]=e[j][4]-e[j][2];   //原来上限-残留量,即为所用(上限-下限-残留+下限)
                   for(int i=1;i<=n;i++)
                     for(int j=n+1;j<=n+m;j++)
                      {
                          if(j!=n+m)printf("%d ",ans[i][j]);
                          else printf("%d
    ",ans[i][j]);
                      }
              }
              if(N!=0)printf("
    ");
        }
          return 0;
    }
    


  • 相关阅读:
    分割回文串(力扣第131题)
    子集 II(力扣第91题)
    子集(力扣第78题)
    组合总和 III(力扣第216题)
    JavaWeb部分 (前序)
    JavaSE部分 (IO流下)
    JavaSE部分 (IO流上)
    JavaSE部分 (File类)
    Leetcode 08.04 幂集 回溯与位图
    Leetcode 1405 最长快乐字符串 穷举与贪心
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925807.html
Copyright © 2011-2022 走看看