[BZOJ4819][SDOI2017]新生舞会(分数规划+费用流,KM)
2018-04-05 11:10
411 查看
4819: [Sdoi2017]新生舞会
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1097 Solved: 566
[Submit][Status][Discuss]Description
学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会 买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出 a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便, 比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然, 还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C athy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a'1,a'2,...,a'n, 假设每对舞伴的不协调程度分别是b'1,b'2,...,b'n。令 C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n),Cathy希望C值最大。Input
第一行一个整数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^4Output
一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等Sample Input
3
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9Sample Output
5.357143HINT
Source
[Submit][Status][Discuss]
有点太裸了,两个算法都非常明显。
”根据答案的式子可以确定是分数规划,根据题目名称‘舞会’可以确定是二分图匹配”然后这题就做完了。
先知道是KM,然后看网上写的都是网络流然后也开始写网络流,写了半天发现是费用流。。
费用流方面并不是普通的最大费用流,因为最后必须全部匹配,所以直接把SPFA成功的条件从一般最大费用流的"dis[T]>0"改成"dis[T]!=-inf"就好了。
#include<cstdio> #include<algorithm> #define rep(i,l,r) for (int i=l; i<=r; i++) #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) using namespace std; const int N=210,M=30100,inf=1000000000; const double eps=1e-10; double ans,c[M],dis ; int n,cnt,mn,S,T,f[M],to[M],nxt[M],q[M],pre ,inq ,h ,a ,b ; void add(int u,int v,int w,double co){ to[++cnt]=v; f[cnt]=w; c[cnt]=co; nxt[cnt]=h[u]; h[u]=cnt; to[++cnt]=u; f[cnt]=0; c[cnt]=-co; nxt[cnt]=h[v]; h[v]=cnt; } bool spfa(){ rep(i,0,T) pre[i]=-1,inq[i]=0,dis[i]=-inf; dis[S]=0; q[1]=S; for (int st=0,ed=1; st<ed; ){ int x=q[++st]; inq[x]=0; For(i,x) if (f[i] && dis[k=to[i]]<dis[x]+c[i]){ dis[k]=dis[x]+c[i]; pre[k]=i; if (!inq[k]) inq[k]=1,q[++ed]=k; } } return dis[T]!=dis[0]; } void work(){ for (ans=0; spfa(); ans+=dis[T]*mn){ mn=inf; for (int i=pre[T]; ~i; i=pre[to[i^1]]) mn=min(mn,f[i]); for (int i=pre[T]; ~i; i=pre[to[i^1]]) f[i]-=mn,f[i^1]+=mn; } } int main(){ freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); scanf("%d",&n); rep(i,1,n) rep(j,1,n) scanf("%d",&a[i][j]); rep(i,1,n) rep(j,1,n) scanf("%d",&b[i][j]); double L=0,R=10000; S=n*2+1,T=n*2+2; while (L+eps<R){ double mid=(L+R)/2; ans=0; rep(i,1,2*n+3) h[i]=0; cnt=1; rep(i,1,n) add(S,i,1,0); rep(i,1,n) add(i+n,T,1,0); rep(i,1,n) rep(j,1,n) add(i,j+n,1,a[i][j]-mid*b[i][j]); work(); if (ans>eps) L=mid; else R=mid; } printf("%.6lf\n",L); return 0; }
KM就没什么好说的了,速度快5倍。果然不能依靠玄学,当然这题的图比较稠密也是原因之一。
原来KM也可以跑负权图。
#include<cstdio> #include<cstring> #include<algorithm> #define rep(i,l,r) for (int i=l; i<=r; i++) #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) using namespace std; const int N=210,inf=1000000000; const double eps=1e-10; int n,lk ,vx ,vy ,a ,b ; double lx ,ly ,w ,s ; double abs(double x){ return (x<0)?-x:x; } bool dfs(int x){ vx[x]=1; rep(y,1,n) if (!vy[y]){ double t=lx[x]+ly[y]-w[x][y]; if (abs(t)<eps){ vy[y]=1; if (lk[y]==-1 || dfs(lk[y])) { lk[y]=x; return 1; } }else s[y]=min(s[y],t); } return 0; } double KM(){ rep(i,1,n) lx[i]=-inf,ly[i]=0,lk[i]=-1; rep(i,1,n) rep(j,1,n) lx[i]=max(lx[i],w[i][j]); rep(x,1,n){ rep(i,1,n) s[i]=inf; while (1){ memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if (dfs(x)) break; double d=inf; rep(i,1,n) if (!vy[i]) d=min(d,s[i]); rep(i,1,n) if (vx[i]) lx[i]-=d; rep(i,1,n) if (vy[i]) ly[i]+=d; else s[i]-=d; } } double res=0; rep(i,1,n) res+=w[lk[i]][i]; return res; } int main(){ freopen("ball.in","r",stdin); freopen("ball.out","w",stdout); scanf("%d",&n); rep(i,1,n) rep(j,1,n) scanf("%d",&a[i][j]); rep(i,1,n) rep(j,1,n) scanf("%d",&b[i][j]); double L=0,R=10000; while (L+eps<R){ double mid=(L+R)/2; rep(i,1,n) rep(j,1,n) w[i][j]=a[i][j]-mid*b[i][j]; if (KM()>eps) L=mid; else R=mid; } printf("%.6lf\n",L); return 0; }
相关文章推荐
- BZOJ.4819.[SDOI2017]新生舞会(01分数规划 费用流SPFA)
- BZOJ 4819:[Sdoi2017]新生舞会 01分数规划+费用流
- BZOJ 4819: [Sdoi2017]新生舞会 01分数规划 二分图最大权匹配(KM算法)/费用流
- 【bzoj4819】[Sdoi2017]新生舞会 分数规划+费用流
- 【BZOJ 4819】 4819: [Sdoi2017]新生舞会 (0-1分数规划、二分+KM)
- BZOJ_4819_[Sdoi2017]新生舞会_01分数规划+费用流
- [BZOJ4819]-[Sdoi2017]新生舞会-01分数规划+费用流
- BZOJ4819 [Sdoi2017]新生舞会 【01分数规划 + 费用流】
- 【BZOJ4819】【SDOI2017】新生舞会 [费用流][分数规划]
- BZOJ 4819 [Sdoi2017]新生舞会 ——费用流 01分数规划
- bzoj4819 [Sdoi2017]新生舞会 01分数规划+二分图最优匹配
- bzoj4819 [Sdoi2017]新生舞会 分数规划(实数二分)+网络流检验
- [bzoj4819][01分数规划][网络流-费用流]新生舞会
- BZOJ4819: [Sdoi2017]新生舞会(01分数规划)
- bzoj 4819: [Sdoi2017]新生舞会 01分数规划 二分图最优匹配
- 4819: [Sdoi2017]新生舞会(分数规划)
- loj #2003. 「SDOI2017」新生舞会(分数规划+费用流)
- LOJ 「SDOI2017」新生舞会(二分 + 分数规划+ 费用流)
- [BZOJ4819][SDOI2017]新生舞会(二分答案+费用流)
- bzoj 4819: [Sdoi2017]新生舞会 二分答案+费用流