题解:
发现那个关于代价的二次函数实际上就是生效的实际贡献数量,然后二分答案,就是一个最大权闭合子图。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
using std::cerr;
using std::cout;
cs int N=5e3+7,M=55;
cs double eps=1e-9;
int S,T,n,tot,id[M][M],p[M][M],st[N],ed[N];
struct edge{int to,rev;double cap;};
typedef std::vector<edge>::iterator iter;
std::vector<edge> G[N];iter cur[N];
inline void adde(int u,int v,double cap){
G[u].push_back((edge){v,G[v].size(),cap});
G[v].push_back((edge){u,G[u].size()-1,0});
}
int lev[N],gap[N],finish;
inline void BFS(){
static int q[N],qn;
memset(lev+1,0,sizeof(int)*tot);
memset(gap+1,0,sizeof(int)*tot);
q[qn=1]=T,lev[T]=gap[1]=1;
for(int re i=1;i<=qn;++i){
int u=q[i];cur[u]=G[u].begin();
for(iter e=G[u].begin();e!=G[u].end();++e)
if(!lev[e->to]){
lev[e->to]=lev[u]+1;
++gap[lev[e->to]];
q[++qn]=e->to;
}
}
finish=lev[S]==0;
}
double dfs(int u,double flow){
if(u==T)return flow;
double ans=0;
for(iter &e=cur[u];e!=G[u].end();++e)
if(e->cap>eps&&lev[e->to]+1==lev[u]){
double delta=dfs(e->to,std::min(flow-ans,e->cap));
if(delta){
e->cap-=delta;
G[e->to][e->rev].cap+=delta;
if(fabs((ans+=delta)-flow)<eps)return ans;
}
}
if(!--gap[lev[u]++])finish=true;
++gap[lev[u]];cur[u]=G[u].begin();
return ans;
}
inline double Flow(){
double flow=0;BFS();
while(!finish)flow+=dfs(S,1e10);
return flow;
}
inline bool calc(double x){
double ans=0;
for(int re i=1;i<=tot;++i)G[i].clear();
for(int re i=1;i<=n;++i)
for(int re j=i+1;j<=n;++j){
adde(S,id[i][j],p[i][j]+2*x);
adde(id[i][j],i,1e10);
adde(id[i][j],j,1e10);
ans+=p[i][j]+2*x;
}
for(int re i=1;i<=n;++i)adde(i,T,x*199);
return ans>Flow()+eps;
}
signed main(){
#ifdef zxyoi
freopen("profit.in","r",stdin);
#endif
scanf("%d",&n);
for(int re i=1;i<=n;++i){
static char s[M];
scanf("%s",s+1);
for(int re j=1;j<=n;++j)p[i][j]=s[j]^48;
}
S=n+1,T=tot=n+2;
for(int re i=1;i<=n;++i)
for(int re j=i+1;j<=n;++j){
id[i][j]=++tot;
st[tot]=i,ed[tot]=j;
}
double l=0,r=1.5,m;
while(l+eps<r)(calc(m=(l+r)/2))?l=m:r=m;
printf("%.7f",l);
return 0;
}