【BZOJ】3698:XWW的难题-上下界网络流

题解

下界为各数下取整的值,取差建立超级源汇点SS,TT跑一遍dinic,先判断是否可以满流,然后再跑原图,ans*3(原值算一遍,右边算一遍,下边算一遍)
详见代码


代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define inf 0x7fffffff
#define db double
using namespace std;
db a[102][102];
int n,S,T,SS,TT,tot=1,in[225],d[225],sum,ans;
int head[250],cur[250],to[1000005],nxt[1000005],w[1000005];
queue<int>Q;
inline void lk(int u,int v,int val)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=val;}
inline int imin(int x,int y){return x>y?y:x;}
inline void build()
{
    int i,j;
    for(i=1;i<=n;++i){
        if(a[i][n]!=(int)a[i][n]) lk(S,i,1),lk(i,S,0);
        in[S]-=(int)a[i][n];in[i]+=(int)a[i][n]; 
    }
    for(i=1;i<=n;++i){
        if(a[n][i]!=(int)a[n][i]) lk(i+n,T,1),lk(T,i+n,0);
        in[i+n]-=(int)a[n][i];in[T]+=(int)a[n][i];
    }
    for(i=1;i<n;++i)
     for(j=1;j<n;++j){
        if(a[i][j]!=(int)a[i][j]) lk(i,j+n,1),lk(j+n,i,0);
        in[i]-=(int)a[i][j];in[j+n]+=(int)a[i][j];
     }
    for(i=1;i<=TT;++i){
        if(in[i]>0){sum+=in[i];lk(SS,i,in[i]);lk(i,SS,0);}
        else if(in[i]<0)lk(i,TT,-in[i]),lk(TT,i,0);
    }
}

inline bool bfs(int s,int t)
{
    int I,J;
    for(I=1;I<=TT;++I) d[I]=-1;
    d[s]=0;Q.push(s);int x;
    while(!Q.empty()){
        x=Q.front();Q.pop();
        for(I=head[x];I;I=nxt[I]){
            J=to[I];
            if(d[J]==-1 && w[I]){
                d[J]=d[x]+1;
                Q.push(J);
            }
        }
    }
    return d[t]!=-1?;
}

inline int dfs(int s,int t,int f)
{
    if(s==t) return f;
    int ss=0,ret;
    for(int i=cur[s],j;i;i=nxt[i]){
        j=to[i];
        if(d[j]==d[s]+1 && w[i]){
            ret=f-ss;ret=dfs(j,t,imin(ret,w[i]));
            w[i]-=ret;w[i^1]+=ret;if(w[i]) cur[s]=i;
            ss+=ret;if(ss==f) return f;
        }
    }
    if(!ss) d[s]=-1;
    return ss;
}

inline void dinic(int s,int t)
{
    while(bfs(s,t)){
        for(int i=1;i<=TT;++i) cur[i]=head[i];
        ans+=dfs(s,t,inf);
    }
}

int main(){
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=n;++i)
     for(j=1;j<=n;++j) scanf("%lf",&a[i][j]);
    S=(n<<1)+1;T=S+1;SS=T+1;TT=SS+1;
    build();
    lk(T,S,inf);lk(S,T,0);
    dinic(SS,TT);
    if(ans!=sum){printf("NO\n");return 0;}
    ans=0;dinic(S,T);
    printf("%d\n",ans*3);
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80556396