XWW的难题(bzoj 3698)

Description

XWW是个影响力很大的人,他有很多的追随者。这些追随者都想要加入XWW教成为XWW的教徒。但是这并不容易,需要通过XWW的考核。
XWW给你出了这么一个难题:XWW给你一个N*N的正实数矩阵A,满足XWW性。
称一个N*N的矩阵满足XWW性当且仅当:(1)A[N][N]=0;(2)矩阵中每行的最后一个元素等于该行前N-1个数的和;(3)矩阵中每列的最后一个元素等于该列前N-1个数的和。
现在你要给A中的数进行取整操作(可以是上取整或者下取整),使得最后的A矩阵仍然满足XWW性。同时XWW还要求A中的元素之和尽量大。

Input

第一行一个整数N,N ≤ 100。
接下来N行每行包含N个绝对值小于等于1000的实数,最多一位小数。

Output

输出一行,即取整后A矩阵的元素之和的最大值。无解输出No。

Sample Input

4
3.1 6.8 7.3 17.2
9.6 2.4 0.7 12.7
3.6 1.2 6.5 11.3
16.3 10.4 14.5 0

Sample Output

129

HINT

 

【数据规模与约定】

有10组数据,n的大小分别为10,20,30...100。

【样例说明】

样例中取整后满足XWW性的和最大的矩阵为:

3 7 8 18

10 3 0 13

4 1 7 12

17 11 15 0

/*
    上下界最大流。
    建立源点SS,从SS向i连一条上下界为(floor(a[i][n]),ceil(a[i][n]))的边;
    建立源点TT,从i'向TT连一条上下界为(floor(a[n][i]),ceil(a[n][i]))的边;
    建立i->i'上下界为(floor(a[i][j]),ceil(a[i][j]))的边。
    跑上下界最大流。 
*/
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#define N 210
#define M 21000
#define inf 1000000000
using namespace std;
int down[N][N],up[N][N],head[N],dis[N],s[N],n,cnt=1,SS,TT,S,T;
struct node{int v,f,pre;}e[M];
queue<int> q;
void add(int u,int v,int f){
    e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
    e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
}
bool bfs(){
    memset(dis,-1,sizeof(dis));
    q.push(S);dis[S]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].pre){
            if(!e[i].f||dis[e[i].v]!=-1) continue;
            dis[e[i].v]=dis[u]+1;
            q.push(e[i].v);
        }
    }
    return dis[T]!=-1;
}
int dinic(int x,int f){
    int rest=f;
    if(x==T) return f;
    for(int i=head[x];i;i=e[i].pre){
        if(!e[i].f||dis[e[i].v]!=dis[x]+1) continue;
        int t=dinic(e[i].v,min(rest,e[i].f));
        e[i].f-=t;e[i^1].f+=t;rest-=t;
    }
    if(rest==f) dis[x]=-1;
    return f-rest;
}
int main(){
    scanf("%d",&n);
    SS=n*2+1;TT=n*2+2;S=n*2+3;T=n*2+4;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            double x;scanf("%lf",&x);
            down[i][j]=int(x);
            up[i][j]=int(x+0.99);
        }
    for(int i=1;i<n;i++){
        if(down[i][n]!=up[i][n]) add(SS,i,1);
        if(down[n][i]!=up[n][i]) add(i+n,TT,1);
        s[SS]+=down[i][n];s[i]-=down[i][n];
        s[i+n]+=down[n][i];s[TT]-=down[n][i];
    }
    for(int i=1;i<n;i++)
        for(int j=1;j<n;j++){
            if(down[i][j]!=up[i][j]) add(i,j+n,1);
            s[i]+=down[i][j];s[j+n]-=down[i][j];
        }
    int tot=0;
    for(int i=1;i<=T;i++){
        if(s[i]>0) add(i,T,s[i]),tot+=s[i];
        if(s[i]<0) add(S,i,-s[i]);
    }
    add(TT,SS,inf);
    int maxflow=0;
    while(bfs()) maxflow+=dinic(S,inf);
    if(maxflow!=tot) {printf("No");return 0;}
    maxflow=0;
    S=SS;T=TT;
    while(bfs()) maxflow+=dinic(S,inf);
    printf("%d",maxflow*3);
    return 0;
}

 

posted @ 2017-03-27 22:16  karles~  阅读(518)  评论(0编辑  收藏  举报