bzoj 2406: 矩阵 上下界网络流判定

2406: 矩阵

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 138  Solved: 46
[Submit][Status][Discuss]

Description

 

Input

第一行两个数nm,表示矩阵的大小。

接下来n行,每行m列,描述矩阵A

最后一行两个数LR

Output

第一行,输出最小的答案;

Sample Input

2 2

0 1

2 1

0 1

Sample Output

1

HINT

对于100%的数据满足N,M<=200,0<=L<=R<=1000,0<=Aij<=1000

 

  看网上没什么题解,就随便写一写吧,二分答案转化为判定问题:构造矩阵,使得每行每列之和分别满足在一个区间内,这就是很裸很裸的带下界网络流判定问题。直接行列分别建点即可,然而我写的时候数组开小了,wa了一个上午。

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 220
#define MAXV MAXN*MAXN
#define MAXE MAXV*2
#define INF 0x3f3f3f3f
#define BIG 100000000
#define abs(x) ((x)<0?(-(x)):(x))
struct Edge
{
        int val,np;
        Edge *next,*neg;
}E[MAXE],*V[MAXV];
int tope=1;
int sour=0,sink=1;
inline void addedge(int x,int y,int z)
{
    //    cout<<"Add edge:<"<<tope+1<<">"<<x<<" "<<y<<":"<<z<<endl;
        E[++tope].np=y;
        E[tope].val=z;
        E[tope].next=V[x];
        V[x]=&E[tope];

        E[++tope].np=x;
        E[tope].val=0;
        E[tope].next=V[y];
        V[y]=&E[tope];

        E[tope].neg=&E[tope-1];
        E[tope-1].neg=&E[tope];
}
int q[MAXV],lev[MAXV];
int vis[MAXV],bfstime=0;
bool bfs()
{
        int head=-1,tail=0;
        Edge *ne;
        lev[sour]=1;
        vis[sour]=++bfstime;
        q[0]=sour;
        while (head<tail)
        {
                for (ne=V[q[++head]];ne;ne=ne->next)
                {
                        if (!ne->val || vis[ne->np]==bfstime)continue;
                        q[++tail]=ne->np;
                        vis[ne->np]=bfstime;
                        lev[ne->np]=lev[q[head]]+1;
                }
        }
        return vis[sink]==bfstime;
}
int dfs(int now,int maxf)
{
        int ret=0,t;
        if (now==sink || !maxf)return maxf;
        Edge* ne;
        for (ne=V[now];ne;ne=ne->next)
        {
                if (!ne->val || lev[ne->np]!=lev[now]+1)continue;
                t=dfs(ne->np,min(maxf,ne->val));
                ne->val-=t;
                ne->neg->val+=t;
                maxf-=t;
                ret+=t;
                //cout<<"Flow:"<<now<<"-"<<ne->np<<":"<<x<<"("<<ne->val<<")"<<endl;
        }
        if (!ret)lev[now]=-1;
        return ret;
}
int dinic()
{
        int ret=0;
        while (bfs())
        {
                ret+=dfs(sour,INF);
        }
        return ret;
}

int mat[MAXN][MAXN];
int degin[MAXV],degout[MAXV];
int main()
{
        freopen("input.txt","r",stdin);
        freopen("output.txt","w",stdout);
        int n,m,a,b;
        scanf("%d%d",&n,&m);
        for (int i=0;i<n;i++)
                for (int j=0;j<m;j++)
                {
                        scanf("%d",&mat[i][j]);
                }
        scanf("%d%d",&a,&b);
        int l=-1,r=100010;
        int tsour=2,tsink=3;
        while (l+1<r)
        {
                memset(degin,0,sizeof(degin));
                memset(degout,0,sizeof(degout));
                memset(V,0,sizeof(V));
                tope=-1;
                int mid=(l+r)>>1;
                for (int i=0;i<n;i++)
                {
                        int s=0;
                        for (int j=0;j<m;j++)
                                s+=mat[i][j];
                        degout[tsour]+=s-mid;
                        degin[4+i]+=s-mid;
                        addedge(tsour,4+i,mid*2);
                }
                for (int i=0;i<m;i++)
                {
                        int s=0;
                        for (int j=0;j<n;j++)
                                s+=mat[j][i];
                        degin[tsink]+=s-mid;
                        degout[4+i+n]+=s-mid;
                        addedge(4+i+n,tsink,mid*2);
                }
                for (int i=0;i<n;i++)
                {
                        for (int j=0;j<m;j++)
                        {
                                degout[4+i]+=a;
                                degin[4+j+n]+=a;
                                addedge(4+i,4+j+n,b-a);
                        }
                }
                addedge(tsink,tsour,BIG);
                int sum=0;
                for (int i=2;i<4+n+m;i++)
                {
                        if (degout[i]>degin[i])
                        {
                                sum+=degout[i]-degin[i];
                                addedge(i,sink,degout[i]-degin[i]);
                        }
                        else if (degin[i]>degout[i])
                                addedge(sour,i,degin[i]-degout[i]);
                }
                if (dinic()==sum)
                        r=mid;
                else
                        l=mid;
        }
        printf("%d
",r);
}

 

 

原文地址:https://www.cnblogs.com/mhy12345/p/4548859.html