1. 程式人生 > >BZOJ3993 星際戰爭 題解(二分+最大流)

BZOJ3993 星際戰爭 題解(二分+最大流)

星際戰爭

【問題描述】

3333年,在銀河系的某星球上,X軍團和Y軍團正在激烈地作戰。在戰鬥的某一階段,Y軍團一共派遣了N個巨型機器人進攻X軍團的陣地,其中第i個巨型機器人的裝甲值為Ai。當一個巨型機器人的裝甲值減少到0或者以下時,這個巨型機器人就被摧毀了。X軍團有M個鐳射武器,其中第i個鐳射武器每秒可以削減一個巨型機器人Bi的裝甲值。鐳射武器的攻擊是連續的。這種鐳射武器非常奇怪,一個鐳射武器只能攻擊一些特定的敵人。Y軍團看到自己的巨型機器人被X軍團一個一個消滅,他們急需下達更多的指令。為了這個目標,Y軍團需要知道X軍團最少需要用多長時間才能將Y軍團的所有巨型機器人摧毀。但是他們不會計算這個問題,因此向你求助。

【資料規模和約定】

對於30%的資料,1<=N, M<=5;

對於全部的資料,1<=N,M<=50,1<=Ai<=105,1<=Bi<=1000,輸入資料保證X軍團一定能摧毀Y軍團的所有巨型機器人。

建立一個網路,源點S,匯點T。S連到所有的鐳射節點,鐳射節點連到能攻擊到的巨人節點,所有巨人節點連到T。

二分時間t,將所有S到鐳射節點的最大流量設定為輸出的攻擊總量Bi*t,巨人節點和T之間的流量設定為Ai。

對這個圖跑最大流,如果最大流等於所有裝甲值之和,說明能在規定時間內能打掉所有巨人,更新上界。否則更新下界。

注意精度問題,float的精度不夠。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#define INF 2333333
using namespace std;
int cnt=0;
const double eps=1e-6;
vector<int> tab[4000];
int n,m;
int dis[4000];
int cur[4000];
double a[55],b[55];
int S,T;
double sum;
struct edge
{
	int u,v;
	double cap;
	edge(int u_,int v_,double cap_){u=u_;v=v_;cap=cap_;} 
	edge(){}
}eg[8000];
void addedge(int u,int v,double c)
{
	eg[cnt]=edge(u,v,c);
	tab[u].push_back(cnt++);
	eg[cnt]=edge(v,u,0);
	tab[v].push_back(cnt++); 
}
void modify(double t)
{
	int i=0;
	for(int j=1;j<=n;i+=2,++j)
	{
		eg[i].cap=a[j];
		eg[i^1].cap=0.0;
	}
	for(int j=1;j<=m;i+=2,++j)
	{
		eg[i].cap=t*b[j];
		eg[i^1].cap=0.0;
	}
	for(;i<cnt;++i)
	{
		if(i&1)eg[i].cap=0.0;
		else eg[i].cap=INF;
	}
}
queue<int> q;
bool bfs()
{
	q.push(S);
	for(int i=S;i<=T;++i)
		dis[i]=INF;
	dis[S]=0;
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		int sz=tab[now].size();
		for(int i=0;i<sz;++i)
		{
			edge& e=eg[tab[now][i]];
			if(dis[e.v]>dis[now]+1&&e.cap>eps)
			{
				dis[e.v]=dis[now]+1;
				q.push(e.v);
			}
		}
	}
	return dis[T]<INF;
}
double dfs(int now,double flow)
{
	if(now==T)return flow;
	int sz=tab[now].size();
	for(int& i=cur[now];i<sz;++i)
	{
		edge& e=eg[tab[now][i]];
		if(dis[now]+1==dis[e.v]&&e.cap>eps)
		{
			double f=dfs(e.v,(double)min(flow,e.cap));
			if(f>eps)
			{
				e.cap-=f;
				eg[tab[now][i]^1].cap+=f;
				return f;
			}
		}
	}
	return 0;
}
double dinic()
{
	double ans=0,flow=0;
	while(bfs())
	{
		memset(cur,0,sizeof(cur));
		while((flow=dfs(S,INF))>eps)
			ans+=flow;
	}
	return ans;
}
bool can(double t)
{
	modify(t);
	double flow=dinic();
	return fabs(flow-sum)<eps;
}
double bsearch(double l,double r)
{
	if(r-l<eps)return (l+r)/2.0;
	double mid = (l+r)/2.0;
	if(can(mid))return bsearch(l,mid);
	else return bsearch(mid,r);
}
int main()
{
	//freopen("war.in","r",stdin);
	//freopen("war.out","w",stdout);
	scanf("%d%d",&n,&m);
	S=1;T=n+m+2;
	for(int i=1;i<=n;++i)
	{
		scanf("%lf",&a[i]);
		sum+=a[i]; 
		addedge(m+i+1,T,a[i]);
	}
	for(int i=1;i<=m;++i)
	{
		scanf("%lf",&b[i]);
		addedge(S,i+1,0.0);
	}
	for(int i=1;i<=m;++i)
	{
		for(int j=1;j<=n;++j)
		{
			int c;
			scanf("%d",&c);
			if(c==1)addedge(i+1,m+j+1,INF);
		}
	}
	printf("%.6lf\n",bsearch(0.0,100010.0));
	return 0;
}