hihoCoder 1389 Sewage Treatment 【二分+网络流+优化】 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

#1389 : Sewage Treatment

时间限制: 2000ms
单点时限: 2000ms
内存限制: 256MB

描述

After years of suffering, people could not tolerate the pollution in the city any more, and started a long-lasting protest. Eventually, the municipal government made up its mind to deal with the sewage discharged by factories. The government planned to deploy some Pollution-Killer Utilities (PKUs) in order to clean all the sewage, and meanwhile, minimize the total cost.

The city can be approximately considered as a plane. There are n factories discharging sewage. The i-th one is located at (xi, yi), and discharges si units of sewage every day. The government has built m PKUs. The PKUs' locations are also fixed, and the j-th one is located at (xj, yj). Two features of PKUs are essential, and you will need to find the best choice of them: u is the upper limit of units of sewage that can be cleaned by one PKU every day, and c is the coverage radius of one PKU (which means, only if the distance between the PKU and the factory does not exceed the coverage radius, sewage discharged by this factory can be cleaned by this PKU). Note that all the PKUs share the same u and c. Because of some technical reasons, u has to be a positive integer.

Here is your task. The cost of deploying these PKUs can be weighed by an empirical formula:

f = u×sqrt(c)

You need to calculate the minimum value of f, and guarantee all the sewage is treated.

输入

There are no more than 15 test cases. Each test case starts with a line containing two positive integers n and m (1 <= n, m <= 100), representing the number of factories and PKUs. Then n lines follow, the i-th line contains three integers xi, yi, si (-10000 <= xi, yi <= 10000, 1 <= si <= 100), representing the i-th factory's location and the quantity of sewage discharged by it every day. In the next following m lines, the j-th line contains two integers xj, yj (-10000 <= xj, yj <= 10000), representing the j-th PKU's location. After each test case there is an empty line. After all the test cases there is a line "0 0", which indicates the end of the input, and should not be processed.

输出

For each test case, output a single line containing a number, which is the minimum value of f. This number should be rounded to an integer.

提示

Test case 1:

When u = 12 and c = 2, f has the minimum value of 12 * sqrt(2) = 16.97 = 17.

Test case 2:

When u = 10, c = sqrt(2), f has the minimum value of 10 * sqrt(sqrt(2)) = 11.89 = 12.

The input guarantees that there is always a valid solution. You may assume that the factories and PKUs are uniformly randomly distributed on the plane.

样例输入
3 1
-1 0 5
2 0 3
0 1 4
0 0

4 2
0 0 4
3 0 5
3 2 3
0 2 6
1 1
2 1

0 0
样例输出
17
12

题目链接:

  http://hihocoder.com/problemset/problem/1389

题目大意:

  N个污水厂fac,M个污水处理厂pku(N,M<=100)。每个污水厂坐标(xi,yi),会产生Si的污水。每个污水处理厂坐标(xi,yi),可以处理距离在C范围内的总量为U的污水(一个污水厂能被多个处理厂一起处理)。

  所有污水处理厂的U,C必须保持相同,求在能处理所有污水的情况下 f=U*√C 函数最小值。(U为正整数,C为欧拉距离,坐标范围在[-10000,10000])

题目思路:

  【二分+网络流+优化】

  首先求出每个污水处理厂b[i].from到每个污水厂b[i].to的欧拉距离b[i].dis,从小到大排序,总共N*M条边。设源S 汇T

  枚举C=b[i].dis(确保每个污水厂都和至少一个污水处理厂相连),二分需要的最小的U

  check时将前i条边都加入到网络流的图中,边的容量为无穷大。S到每个污水处理厂连一条容量为U的边,每个污水厂到T连一条容量为Si的边

    然后从S到T跑最大流看是否等于总污水量sum。等于就表明当前U可行,否则当前U不可行。

  光这样做会T,需要优化,二分U的上界为当前可行的最小的U(因为C在不断增大,f只有在U减小的情况下才可能更优),下界为sum/n,表示每个污水处理厂至少处理的均摊量。

  再加一个优化 当前枚举的C和二分下界l算出的函数f已经超过f的最优值时就break(再往后答案不会更优)。

  【我也不知道为什么这样就过了。比赛的时候觉得会T就没写。。结果看了大牛的题解发现真的是这么做。不过比赛的时候优化没想清楚可能还会T】



//
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<bitset>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-10)
#define J 10000
#define mod 1000000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define N 204
#define M 20004
using namespace std;
typedef long long LL;
double anss;
LL aans,sum;
int cas,cass;
int n,m,lll,ans;
int C,U,S,T,nn;
int d[N],vd[N],last[N];
int mapp[N][N];
bool mark[N];
struct Point
{
	int x,y,qq;
}fac[N],pku[N];
struct Edge
{
	int from,to,dis;
}b[M];
struct xxx
{
	int from,to,next,q;
}a[M<<1];
bool cmp1(Point aa,Point bb)
{
	if(aa.x!=bb.x)return aa.x<bb.x;
	return aa.y<bb.y;
}
bool cmp2(Edge aa,Edge bb)
{
	return aa.dis<bb.dis;
}
void add(int x,int y,int z)
{
	a[++lll].to=y;
	a[lll].q=z;
	a[lll].next=last[x];
	last[x]=lll;
}
int sap(int u,int f)
{
	int i,v,tt,asp=0,mix=nn-1;
	if(u==T)return f;
	for(i=last[u];i!=0;i=a[i].next)
	{
		v=a[i].to;
		if(a[i].q>0)
		{
			if(d[u]==d[v]+1)
			{
				tt=sap(v,min(f-asp,a[i].q));
				asp+=tt;
				a[i].q-=tt;
				a[i^1].q+=tt;
				if(asp==f || d[S]==nn)
					return asp;
			}
			mix=min(mix,d[v]);
		}
	}
	if(asp!=0)return asp;
	if(!--vd[d[u]])d[S]=nn;
	else vd[d[u]=mix+1]++;
	return asp;
}
bool check(int u)
{
	int i,f;
	mem(d,0);mem(vd,0);
	nn=T;
	vd[0]=nn;
	ans=0;
	while(d[S]<nn)
	{
		f=sap(S,MAX);
		ans+=f;
	}
	if(ans==sum)return 1;
	return 0;
}
void build(int k,int uu)
{
	int i;
	mem(last,0);lll=1;
	for(i=1;i<=m;i++)
		add(S,i,uu),add(i,S,0);
	for(i=1;i<=n;i++)
		add(m+i,T,fac[i].qq),add(T,m+i,0);
	for(i=1;i<=k;i++)
		add(b[i].from,b[i].to+m,MAX),add(b[i].to+m,b[i].from,0);
}
int main()
{
	#ifndef ONLINE_JUDGEW
//	freopen("1.txt","r",stdin);
//	freopen("2.txt","w",stdout);
	#endif
	int i,j,k;
	int x,y,z,l,r,mid;
//	init();
//	for(scanf("%d",&cass);cass;cass--)
//	for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
//	while(~scanf("%s",s))
	while(~scanf("%d%d",&n,&m))
	{
		sum=0;cas=0;anss=1e30;ans=0;
		mem(mark,0);
		if(!n && !m)break;
		for(i=1;i<=n;i++)
		{
			scanf("%d%d%d",&fac[i].x,&fac[i].y,&fac[i].qq);
			sum+=fac[i].qq;
		}
		for(i=1;i<=m;i++)
			scanf("%d%d",&pku[i].x,&pku[i].y);
		//sort(fac+1,fac+1+n,cmp1);
		//sort(pku+1,pku+1+m,cmp1);
		for(i=1;i<=m;i++)
		{
			for(j=1;j<=n;j++)
			{
				b[++cas].from=i;
				b[cas].to=j;
				b[cas].dis=sqr(fac[j].x-pku[i].x)+sqr(fac[j].y-pku[i].y);
			}
		}
		sort(b+1,b+1+cas,cmp2);
		S=n+m+1,T=n+m+2;
		for(j=0,k=1;k<=cas;k++)
		{
			if(!mark[b[k].to])
			{
				j++,mark[b[k].to]=1;
				if(j==n)break;
			}
		}
		U=sum;
		for(;k<=cas;k++)
		{
			C=b[k].dis;
			l=sum/n,r=U;
			if((double)l*sqrt(sqrt(C))>anss)break;
			while(l<r)
			{
				mid=(l+r)>>1;
				build(k,mid);
				if(check(mid))r=mid;
				else l=mid+1;
			}
			U=min(U,r);
			anss=min(anss,U*sqrt(sqrt(C)));
		}
		printf("%d\n",int(anss+0.5));
	}
	return 0;
}
/*
//

//
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值