P3705 [SDOI2017]新生舞会(分数规划&费用流)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3705 [SDOI2017]新生舞会(分数规划&费用流)相关的知识,希望对你有一定的参考价值。
P3705 [SDOI2017]新生舞会(分数规划&费用流)
显然二分后,然后就是找 n n n对 满足属性值 ∑ a i , j − m i d × b i , j ≥ 0 \\sum a_{i,j}-mid\\times b_{i,j}\\ge 0 ∑ai,j−mid×bi,j≥0。
因为每行每列只有一个点,可以使用费用流,源点与每行流量为1,费用为0,汇点与每列流量为 1,费用为0.
第 i i i行 j j j列连边 a i , j − m i d × b i , j a_{i,j}-mid\\times b_{i,j} ai,j−mid×bi,j。
然后跑最大费用流即可。
// Problem: P3705 [SDOI2017]新生舞会
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3705
// Memory Limit: 250 MB
// Time Limit: 1500 ms
// Date: 2021-08-23 14:46:43
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=105,M=205,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
int cnt=1,h[M],flow[M],vis[M],n,m,st,ed;
double dis[M];
ll mf;
double mc;
int id(int x,int y){
return (x-1)*n+y;
}
queue<int>q;
struct edge{
int to,nt;
int f;
double w;//f:flow ,w:cost
}e[M*M*4];
struct Pre{
int i,u;
}pre[M*M*4];//记录前驱结点和边的信息,便于更新残余网络,建立反边.(反悔和贪心的思想)
void add(int u,int v,int f,double w){
e[++cnt]={v,h[u],f,w},h[u]=cnt;
e[++cnt]={u,h[v],0,-w},h[v]=cnt;
}
bool spfa(){// 跑spfa
for(int i=st;i<=ed;i++) dis[i]=-1e18;
mst(flow,0x3f),mst(vis,0); //初始化.
q.push(st),vis[st]=1,dis[st]=0,pre[ed].u=-1;//预处理
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;
int f=e[i].f;
double w=e[i].w;
if(f>0&&dis[v]<dis[u]+w){
dis[v]=dis[u]+w;
pre[v].u=u,pre[v].i=i;
flow[v]=min(flow[u],f);
if(!vis[v]) vis[v]=1,q.push(v);
}
}
}
return pre[ed].u!=-1;
}
void MCMF(){ //MIncost Maxflow
while(spfa()){
int u=ed,x=flow[ed];
mf+=x;
mc+=x*dis[u];
while(u!=st){
e[pre[u].i].f-=x;
e[pre[u].i^1].f+=x;
u=pre[u].u;
}
}
}
int A[N][N],B[N][N];
bool ck(double x){
cnt=1,mst(h,0);
for(int i=1;i<=n;i++)
add(st,i,1,0),add(i+n,ed,1,0);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
add(i,j+n,1,A[i][j]-x*B[i][j]);
mc=mf=0;
MCMF();return mc>=0;
}
const double eps=1e-8;
int main(){
scanf("%d",&n);st=0,ed=(n<<1)+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%d",&A[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%d",&B[i][j]);
double l=0,r=1e4;
while(r-l>eps){
double mid=(l+r)/2.0;
if(ck(mid)) l=mid;
else r=mid;
}
printf("%.6f\\n",l);
return 0;
}
以上是关于P3705 [SDOI2017]新生舞会(分数规划&费用流)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4819: [Sdoi2017]新生舞会(01分数规划)
BZOJ_4819_[Sdoi2017]新生舞会_01分数规划+费用流
bzoj4819[Sdoi2017]新生舞会 分数规划+费用流