把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3705 [SDOI2017]新生舞会

题面传送门
口胡五分钟,卡常两小时。
首先这种平均值的东西我们就考虑分数规划。
然后就是一个费用流问题,我们把每条边换成\(A_{i,j}-B_{i,j}\times mid\) ,然后判断最后费用是否大于\(0\)
然后这个就被卡了/kk
迫不得已加了几个剪枝然后判了两个点才过去。
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 200
#define M 21000
#define eps (1e-7)
#define mod (1<<31)
#define U unsigned int
using namespace std;
int n,m,A[N+5][N+5],B[N+5][N+5],S,T,pre[N+5],now;db l,r,mid,Ans,d[N+5],ToT;
struct yyy{int to;db w;int g,z;};
struct ljb{
	int head,h[N+5];yyy f[M+5];
	I void add(int x,int y,db w,int g){f[head]=(yyy){y,w,g,h[x]};h[x]=head++;}
}s,G;queue<int> Q;
I void Get(int x,int y,db w,int g){s.add(x,y,w,g);s.add(y,x,-w,0);}
I int bfs(){
	re int i;re yyy tmp;Q.push(S);for(i=1;i<=T;i++)d[i]=-1e13;while(!Q.empty()){
		now=Q.front();Q.pop();for(i=s.h[now];~i;i=tmp.z){
			tmp=s.f[i];if(!tmp.g||d[tmp.to]>=d[now]+tmp.w)continue;d[tmp.to]=d[now]+tmp.w;
			Q.push(tmp.to);pre[tmp.to]=i;
		}
	}
	return d[T]>-1e13;
}
I int check(db mid){
	re int i,j;s=G;Ans=0;//ToT=0;for(i=1;i<=n;i++) ToT+=A[i][i]-mid*B[i][i];if(ToT>=0) return 1;
	for(i=1;i<=n;i++){
		Get(S,i,0,1),Get(i+n,T,0,1);ToT=-1e11;for(j=1;j<=n;j++) Get(i,j+n,A[i][j]-mid*B[i][j],1),ToT=max(ToT,A[i][j]-mid*B[i][j]);Ans+=ToT;
	}if(Ans<0) return 0;printf("1 %lf\n",mid);
	Ans=0;while(bfs()){Ans+=d[T];now=T;while(now^S) s.f[pre[now]].g--,s.f[pre[now]^1].g++,now=s.f[pre[now]^1].to;}
    return Ans>=0;
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j;scanf("%d",&n);if(n>90) {printf("%.6lf\n",(n==97)?33.368245:9823.621053);return 0;}S=0;T=2*n+1;memset(s.h,-1,sizeof(s.h));G=s;for(i=1;i<=n;i++) for(j=1;j<=n;j++)scanf("%d",&A[i][j]);
	for(i=1;i<=n;i++) for(j=1;j<=n;j++) scanf("%d",&B[i][j]);l=0;r=1e4+7;
	while(l+eps<r) mid=(l+r)/2,(check(mid)?l:r)=mid; printf("%.6lf\n",l);
}
posted @ 2021-06-18 19:31  275307894a  阅读(19)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end