XWW给你一个N*N的正实数矩阵A,满足XWW性。
称一个N*N的矩阵满足XWW性当且仅当:(1)A[N][N]=0;(2)矩阵中每行的最后一个元素等于该行前N-1个数的和;(3)矩阵中每列的最后一个元素等于该列前N-1个数的和。
现在你要给A中的数进行取整操作(可以是上取整或者下取整),使得最后的A矩阵仍然满足XWW性。同时XWW还要求A中的元素之和尽量大。
第一行一个整数N,N ≤ 100。
接下来N行每行包含N个绝对值小于等于1000的实数,最多一位小数
输出一行,即取整后A矩阵的元素之和的最大值。无解输出No。
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
129
题解
上下界网络流的最大流模板题
有一个小细节:当遇到3.0这种情况时,它无论上取整还是下取整都是3
以为可以A了
然后一直过不了样例
和xmy大佬调了30min
因为有一个极其隐蔽的错误:
SAP在写gap优化的时候要把点数预留准确!!!!
ans=cap[cnt];S=ss;T=tt;
//fir[ss]=nxt[fir[ss]];
//fir[tt]=nxt[fir[tt]];
cap[cnt]=cap[cnt^1]=0;
f();ans+=flow;
printf("%d",3*ans);
因为这一段中没有把原来的S和T删掉,所以有可能还会走到原来的源汇点
如果此时点数已经更新为了2*n+2,那么可能导致gap[0]直接减小到为0(因为你可能删2*n+4个点)
所以,要么重新建图,要么把点数预留为原来的点数
(以后再也不用 T 来表示图中点的数目了。。。)
一定要在外面用一个sz来存
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
#define N 505
#define M 400005
const int INF=0x3f3f3f3f;
int fir[N],to[M],nxt[M],cap[M],cnt;
int ind[N],oud[N],sum;
void adde(int a,int b,int l,int r)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cap[cnt]=r-l;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cap[cnt]=0;
ind[b]+=l;oud[a]+=l;
}
int S,T,flow,d[N],vd[N];
int sz;
int sap(int u,int aug)
{
if(u==T) return aug;
int ret=0,tmp,mind=sz-1;
for(int v,p=fir[u];p;p=nxt[p]){
v=to[p];
if(cap[p]>0){
if(d[u]==d[v]+1){
tmp=sap(v,min(cap[p],aug));
aug-=tmp;cap[p]-=tmp;
ret+=tmp;cap[p^1]+=tmp;
if(d[S]>=sz) return ret;
if(aug==0) break;
}
mind=min(mind,d[v]);
}
}
if(ret==0){
vd[d[u]]--;
if(!vd[d[u]])
d[S]=sz;
d[u]=mind+1;
vd[d[u]]++;
}
return ret;
}
void f()
{
memset(d,0,sizeof(d));
memset(vd,0,sizeof(vd));
sz=2*n+4;
vd[0]=sz;flow=0;
while(d[S]<sz)
flow+=sap(S,INF);
}
int l[N][N],r[N][N];
int main()
{
cnt=1;
int i,j;float x;
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++){
scanf("%f",&x);
l[i][j]=int(floor(x));
r[i][j]=int(ceil(x));
}
n--;
int ss=2*n+1,tt=2*n+2;
S=2*n+3;T=2*n+4;
for(i=1;i<=n;i++){
adde(ss,i,l[i][n+1],r[i][n+1]);
adde(i+n,tt,l[n+1][i],r[n+1][i]);
for(j=1;j<=n;j++)
adde(i,j+n,l[i][j],r[i][j]);
}
for(i=1;i<=2*n+2;i++){
if(ind[i]>oud[i]){adde(S,i,0,ind[i]-oud[i]);sum+=ind[i]-oud[i];}
if(ind[i]<oud[i]) adde(i,T,0,oud[i]-ind[i]);
}
adde(tt,ss,0,INF);
//printf("%d\n",cnt);
int ans=0;
f();
if(flow!=sum){
printf("No");
return 0;
}
ans=cap[cnt];S=ss;T=tt;
//fir[ss]=nxt[fir[ss]];
//fir[tt]=nxt[fir[tt]];
cap[cnt]=cap[cnt^1]=0;
f();ans+=flow;
printf("%d",3*ans);
}