如果正向思考直接求出T
你会发现每一个激光用的时间是不同的
很难求出
但是如果我们二分T
问题就转化成为如何检测在T的时间内能否消灭所有的机器人
比较明显的网络流
我们将S连向所有的激光,权值为\(a_i*t\)
再将所有的激光连向所用能打的机器人,权值为INF
在将机器人连向E,权值为\(b_i\)
检查的是时候我们只需要检查这个图的最大流是不是\(\sum_{i=1}^n b_i\)就行了
#include<iostream>
#include<vector>
#include<cstdio>
#include<climits>
#include<cstring>
using namespace std;
int n,m;
long long summ;
long long l,r,mid;
long long a[105];
long long b[105];
long long k[55][55];
struct networt_flow_isap
{
#define MAXN 405
long long c[MAXN][MAXN];
int d[MAXN];
int vd[MAXN];
long long maxx;
int s,t;
vector<int> g[MAXN];
#undef MAXN
void init()
{
maxx=0;
memset(c,0,sizeof(c));
memset(d,0,sizeof(d));
memset(vd,0,sizeof(vd));
for(int i=1;i<=n;i++)
g[i].clear();
n=n-m-2;
summ=0;
for(int i=1;i<=n;i++)
{
c[i+m][n+m+2]=a[i]*10000;
summ+=a[i]*10000;
g[i+m].push_back(n+m+2);
g[n+m+2].push_back(i+m);
}
for(int i=1;i<=m;i++)
{
c[n+m+1][i]=b[i];
g[n+m+1].push_back(i);
g[i].push_back(n+m+1);
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(k[i][j])
{
c[i][j+m]=(1ll<<40);
g[i].push_back(j+m);
g[j+m].push_back(i);
}
}
}
n=n+m+2;
}
long long dfs(int u,long long f)
{
if(u==t)
return f;
long long minn=0,summ=0,id=n-1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(c[u][v]>0)
{
if(d[u]==d[v]+1)
{
minn=min(f-summ,c[u][v]);
minn=dfs(v,minn);
c[u][v]-=minn;
c[v][u]+=minn;
summ+=minn;
if(d[s]>=n)
return summ;
if(summ==f)
break;
}
if(d[v]<id)
id=d[v];
}
}
if(summ==0)
{
vd[d[u]]--;
if(!vd[d[u]])
d[s]=n;
d[u]=id+1;
vd[d[u]]++;
}
return summ;
}
long long isap(int S,int T)
{
memset(d,0,sizeof(d));
memset(vd,0,sizeof(vd));
s=S;
t=T;
vd[0]=n;
maxx=0;
while(d[s]<n)
maxx+=dfs(s,(1ll<<40)/2);
return maxx;
}
}g;
bool check(long long t)
{
g.init();
for(int i=0;i<g.g[n-1].size();i++)
g.c[n-1][g.g[n-1][i]]*=t;
long long ans=g.isap(n-1,n);
//printf("%lld\n",ans);
for(int i=0;i<g.g[n-1].size();i++)
g.c[n-1][g.g[n-1][i]]/=t;
if(ans>=summ)
return 1;
return 0;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>k[i][j];
n=n+m+2;
l=0;
r=(1ll<<40);
while(l+1<r)
{
mid=(l+r)/2;
if(check(mid))
r=mid;
else
l=mid;
}
printf("%.6lf\n",r*1.0/10000);
return 0;
}
原文:https://www.cnblogs.com/loney-s/p/12025360.html