BZOJ 2285 [Sdoi2011]保密

题解:

求比值用分数规划,单个求太慢了套整体二分

然后求二分图最小割

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const double eps=1e-10;
const int maxn=1000;
const int oo=1000000000;

int n,m;
int n1,m1;
double val[maxn];

int dcmp(double x){
	if(fabs(x)<eps)return 0;
	if(x<0)return -1;
	else return 1;
}

struct ShortestPath{
	int rx[100009],ry[100009],s[100009],t[100009];
	int cntedge;
	int head[maxn];
	int to[100009],nex[100009];
	double dist[100009];
	void Addedge(int x,int y,double z){
		nex[++cntedge]=head[x];
		to[cntedge]=y;
		dist[cntedge]=z;
		head[x]=cntedge;
	}
	
	void readin(){
		for(int i=1;i<=m;++i)scanf("%d%d%d%d",&rx[i],&ry[i],&t[i],&s[i]);
	}
	
	queue<int>q;
	int inq[maxn];
	double d[maxn];
	void Spfa(){
		for(int i=1;i<=n;++i){
			d[i]=oo;inq[i]=0;
		}
		inq[n]=1;d[n]=0;q.push(n);
		while(!q.empty()){
			int x=q.front();q.pop();inq[x]=0;
			for(int i=head[x];i;i=nex[i]){
				if(d[x]+dist[i]<d[to[i]]){
					d[to[i]]=d[x]+dist[i];
					if(!inq[to[i]]){
						q.push(to[i]);
						inq[to[i]]=1;
					}
				}
			}
		}
	}
	
	int a[maxn],b[maxn],c[maxn];
	void Div(int l,int r,double Lo,double Hi){
		if(l>r)return;
		if(dcmp(Lo-Hi)==0){
			for(int i=l;i<=r;++i)val[a[i]]=Lo;
			return;
		}
		double midans=(Lo+Hi)/2.0;
		memset(head,0,sizeof(head));
		cntedge=0;
		for(int i=1;i<=m;++i)Addedge(rx[i],ry[i],t[i]-midans*s[i]);
		Spfa();
		int t1=0,t2=0;
		for(int i=l;i<=r;++i){
			if(d[a[i]]<=0){
				b[++t1]=a[i];
			}else{
				c[++t2]=a[i];
			}
		}
		for(int i=1;i<=t1;++i)a[l+i-1]=b[i];
		for(int i=1;i<=t2;++i)a[l+t1+i-1]=c[i];
		Div(l,l+t1-1,Lo,midans);
		Div(l+t1,r,midans,Hi);
	}
	void Getst(){
		for(int i=1;i<=n1;++i)a[i]=i;
		for(int i=1;i<=n1;++i)val[i]=oo;
		Div(1,n1,0,1000.0);
	}
}P;


struct NetworkFlow{
	struct Edge{
		int from,to;
		double cap,flow;
	};
	vector<int>G[maxn];
	vector<Edge>edges;
	void Addedge(int x,int y,double z){
		Edge e;
		e.from=x;e.to=y;e.cap=z;e.flow=0;
		edges.push_back(e);
		e.from=y;e.to=x;e.cap=0;e.flow=0;
		edges.push_back(e);
		int c=edges.size();
		G[x].push_back(c-2);
		G[y].push_back(c-1);
	}
	
	int s,t;
	int d[maxn];
	int vis[maxn];
	queue<int>q;
	int Bfs(){
		memset(vis,0,sizeof(vis));
		vis[s]=1;d[s]=0;q.push(s);
		while(!q.empty()){
			int x=q.front();q.pop();
			for(int i=0;i<G[x].size();++i){
				Edge e=edges[G[x][i]];
				if((dcmp(e.cap-e.flow)>0)&&(!vis[e.to])){
					vis[e.to]=1;
					d[e.to]=d[x]+1;
					q.push(e.to);
				}
			}
		}
		return vis[t];
	}
	
	double Dfs(int x,double a){
		if((x==t)||(dcmp(a)==0))return a;
		
		double nowflow=0,f=0;
		for(int i=0;i<G[x].size();++i){
			Edge e=edges[G[x][i]];
			if(d[x]+1==d[e.to]){
				f=Dfs(e.to,min(a,e.cap-e.flow));
				if(dcmp(f)>0){
					nowflow+=f;
					a-=f;
					edges[G[x][i]].flow+=f;
					edges[G[x][i]^1].flow-=f;
					if(dcmp(a)==0)break;
				}
			}
		}
		return nowflow;
	}
	
	double Maxflow(){
		double flow=0;
		while(Bfs())flow+=Dfs(s,oo*1.0);
		return flow;
	}
	
	void Sol(){
		s=n1+1;t=s+1;
		for(int i=1;i<=n1;++i){
			if(i%2)Addedge(s,i,val[i]);
			else Addedge(i,t,val[i]);
		}
		while(m1--){
			int x,y;
			scanf("%d%d",&x,&y);
			if((dcmp(val[x]-1000)==0)&&(dcmp(val[y]-1000)==0)){
				printf("-1
");return;
			}
			Addedge(x,y,oo*1.0);
		}
		printf("%.1f
",Maxflow());
	}
}F;

int main(){
	scanf("%d%d",&n,&m);
	P.readin();
	scanf("%d%d",&m1,&n1);
	P.Getst();
	F.Sol();
	return 0;
}

  

自己还是太辣鸡了
原文地址:https://www.cnblogs.com/zzyer/p/8546386.html