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
题解:
n行n列分别看成n个点,s为源点,t为汇点.
s向每一行i连a[i][n]的边.
每一列i向t连a[n][i]的边.
每一行i向每一行j连a[i][j]的边.
这里的a值是有取值范围的.所以就是求有源有汇有上下界的最大流.
具体求法就是
1.从t向s连一条inf的边,把图变成无源无汇,
2.新建源汇S,T,按有上下界的方法建图.
3.求S,T的最大流,检验如果S连出去的边都满流代表合法.
4.求s,t的最大流即是答案.
注意最后答案要乘3,因为一个点会在它这个位置,这一行的末尾,这一列的末尾算三次.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 300
#define M 40000
#define inf 210000000
using namespace std;
int point[N],next[M<<1],n,m,sum,s,t,S,T,cnt=1;
int pre[N],gap[N],dis[N],d[N],cur[N];
double a[N][N];
struct use{
int st,en,v;
}e[M<<1];
void add(int x,int y,int v){
next[++cnt]=point[x];point[x]=cnt;
e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;
next[++cnt]=point[y];point[y]=cnt;
e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;
}
int isap(int ss,int tt){
int mn,u=ss,i,ans(0);
gap[0]=tt;
for (int i=1;i<=tt;i++) gap[i]=0;
for (int i=1;i<=tt;i++) dis[i]=0;
for (int i=1;i<=tt;i++) cur[i]=point[i];
while (dis[ss]<tt){
bool f=false;
for (i=cur[u];i;i=next[i])
if (e[i].v&&dis[e[i].en]+1==dis[u]){f=true;cur[u]=i;break;}
if (f){
pre[u=e[i].en]=i;
if (u==tt){
mn=inf;
for (int i=tt;i!=ss;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);
ans+=mn;
for (int i=tt;i!=ss;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;
u=ss;
}
}
else{
gap[dis[u]]--;if (!gap[dis[u]]) return ans;
for (mn=tt,i=point[u];i;i=next[i]) if (e[i].v) mn=min(mn,dis[e[i].en]);
gap[dis[u]=mn+1]++;cur[u]=point[u];if (u!=ss) u=e[pre[u]].st;
}
}
return ans;
}
void build(){
add(t,s,inf);
for (int i=1;i<n;i++){
if (a[i][n]!=(int)a[i][n]) add(s,i,1);
d[s]-=(int)a[i][n];d[i]+=(int)a[i][n];
}
for (int i=1;i<n;i++){
if (a[n][i]!=(int)a[n][i])add(i+n,t,1);
d[t]+=(int)a[n][i];d[i+n]-=(int)a[n][i];
}
for (int i=1;i<n;i++)
for (int j=1;j<n;j++){
if (a[i][j]!=(int)a[i][j]) add(i,j+n,1);
d[i]-=(int)a[i][j];d[j+n]+=(int)a[i][j];
}
for (int i=1;i<=t;i++)
if (d[i]>0) add(S,i,d[i]),sum+=d[i];
else if (d[i]<0) add(i,T,-d[i]);
}
int main(){
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
scanf("%lf",&a[i][j]);
s=2*n+1,t=s+1;S=t+1;T=S+1;
build();
if (isap(S,T)!=sum){printf("No\n");return 0;};
printf("%d\n",isap(s,t)*3);
}