NC20392. [SDOI2017]新生舞会
描述
输入描述
第一行一个整数n。
接下来n行,每行n个整数,第i行第j个数表示a[i][j]。
接下来n行,每行n个整数,第i行第j个数表示b[i][j]。
1 ≤ n ≤ 100,1 ≤ a[i][j],b[i][j] ≤ 10^4
输出描述
一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等
示例1
输入:
3 19 17 16 25 24 23 35 36 31 9 5 6 3 4 2 7 8 9
输出:
5.357143
C++(clang++ 11.0.1) 解法, 执行用时: 1061ms, 内存消耗: 940K, 提交时间: 2022-10-11 14:57:43
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 105; const double eps = 1e-8; struct edge{int to,nxt,w;double cost;}G[N*N<<2]; int n,a[N][N],b[N][N],head[N<<1],cnt,S,T,vis[N<<1],pe[N<<1]; double dis[N<<1],ans;queue<int>Q; void link(int u,int v,int w,double cost){ G[++cnt]=(edge){v,head[u],w,cost};head[u]=cnt; G[++cnt]=(edge){u,head[v],0,-cost};head[v]=cnt; } bool spfa(){ memset(dis,0xfe,sizeof(dis)); dis[S]=0;Q.push(S); while (!Q.empty()){ int u=Q.front();Q.pop(); for (int e=head[u];e;e=G[e].nxt){ int v=G[e].to; if (G[e].w&&dis[v]<dis[u]+G[e].cost){ dis[v]=dis[u]+G[e].cost;pe[v]=e; if (!vis[v]) vis[v]=1,Q.push(v); } } vis[u]=0; } if (dis[T]==dis[0]) return false; ans+=dis[T]; for (int i=T;i!=S;i=G[pe[i]^1].to) --G[pe[i]].w,++G[pe[i]^1].w; return true; } bool check(double k){ memset(head,0,sizeof(head));cnt=1; for (int i=1;i<=n;++i) link(S,i,1,0),link(i+n,T,1,0); for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) link(i,j+n,1,(double)a[i][j]-k*b[i][j]); ans=0; while (spfa()) ; return ans>-eps; } int main(){ n=gi();S=2*n+1;T=S+1; for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) a[i][j]=gi(); for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) b[i][j]=gi(); double l=0,r=10000; while (r-l>eps){ double mid=(l+r)/2; if (check(mid)) l=mid; else r=mid; } printf("%.6lf\n",l); return 0; }