您的位置:首页 > 其它

BZOJ3993 星际战争(最大流)

2016-03-20 21:49 381 查看
显然这是一个二分图。我们假设在k时间内能够摧毁所有机器人,那么第i个激光武器总共能够削弱k∗Bik*B_i的装甲值。也就是说,∑k∗Bi≥∑Ai \sum k*B_i \geq \sum A_i。那么构建一张网络流的图,s向激光武器连边,容量为k∗Bik*B_i,激光武器向对应的机器人连边,容量为inf,机器人向t连边容量为AiA_i。决策满足单调性,二分最短时间k;最后判断是否满流(我也不知道为什么判断maxflow是否大于∑Ai\sum A_i就WA了,估计精度被卡)。

#include<cstdio>
#include<cstring>
#include<vector>
#define MAXN 3010
#define INF 1e10
#define eps 1e-7
using namespace std;
inline double Min(double a,double b)
{return a<b?a:b;}
struct E
{
int v,op;
double w;
E(){}
E(int a,double b,int c)
{v = a; w = b; op = c;}
};
vector<E> g[MAXN];
int d[MAXN],vd[MAXN],n,m,s,t;
int a[MAXN],b[MAXN];
double sum,flow;
void add(int u,int v,double w)
{
g[u].push_back(E(v,w,g[v].size()));
g[v].push_back(E(u,0.0,g[u].size()-1));
}
double aug(int i,double augco)
{
int j,sz = g[i].size(),mind = t-1;
double delta,augc = augco;
if(i == t) return augco;

for(j = 0; j < sz; j++)
{
int v = g[i][j].v;
if(g[i][j].w > 0)
{
if(d[i] == d[v]+1)
{
delta = Min(augc,g[i][j].w);
delta = aug(v,delta);
g[i][j].w -= delta;
g[v][g[i][j].op].w += delta;
augc -= delta;
if(d[s] >= t) return augco-augc;
if(augc <= 0) break;
}
if(d[v] < mind) mind = d[v];
}
}
if(augc == augco)
{
vd[d[i]]--;
if(!vd[d[i]]) d[s] = t;
d[i] = mind+1;
vd[d[i]]++;
}
return augco-augc;
}
void sap()
{
flow = 0;
memset(d,0,sizeof d);
memset(vd,0,sizeof vd);
vd[0] = t;
while(d[s] < t)
flow += aug(s,(double)INF);
}
bool check(double k)
{
int i = 0,j,sz = g[s].size(),v;
for(i = 0; i < sz; i++)
{
v = g[s][i].v;
g[s][i].w = (double)b[v-n]*k;
g[v][g[s][i].op].w = 0.0;
}
for(i = 1; i <= n; i++)
{
sz = g[i].size();
for(j = 0; j < sz; j++)
{
v = g[i][j].v;
if(v == t) g[i][j].w = (double)a[i],g[t][g[i][j].op].w = 0.0;
else g[i][j].w = 0.0,g[v][g[i][j].op].w = (double)INF;
}
}
sap();
for(i = 1; i <= n; i++)
{
sz = g[i].size();
for(j = 0; j < sz; j++)
{
v = g[i][j].v;
if(v != t) continue;
if(g[i][j].w > eps) return false;
}
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
s = n+m+1,t = s+1;
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
add(i,t,(double)a[i]);
//sum += (double)a[i];
}
for(int i = 1; i <= m; i++)
{
scanf("%d",&b[i]);
add(s,i+n,(double)b[i]);
}
int x;
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
{
scanf("%d",&x);
if(x) add(i+n,j,(double)INF);
}
double l = 0,r = 5e6,mid,ans;
while(r-l>eps)
{
mid = (l+r)/2;
if(check(mid)) r = mid,ans = mid;
else l = mid;
}
printf("%lf\n",(l+r)/2);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: