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
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; }