BZOJ 3994 (思路最大流)

因为用时可以二分,所以先二分最小值,那么判断用最大流就可以了。

好像不用解释什么,对于源点对每个装备连一条边,边权为时间*装备杀伤力,经过可行性矩阵 ,流向n个机器人,每个机器人向汇点流自己的防御值。

那么如果最大流等于所有机器人防御值之和,那么最大流方案,既是该时间下的可行性方案。

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <list>
#include <cstdlib>
#include <queue>
#include <stack>
#include <cmath>
#include <bitset>
#include <cassert>
#define ALL(a) a.begin(), a.end()
#define clr(a, x) memset(a, x, sizeof a)
#define X first
#define Y second
#define pb push_back
#define lowbit(x) (x&(-x))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define rep1(i,x,y) for(int i=x;i<=y;i++)
#define rep(i,n) for(int i=0;i<(int)n;i++)
using namespace std;
const double eps = 1e-6;
typedef long long LL;
typedef long long ll;
typedef pair<int, int> pii;
const int oo =0x3f3f3f3f;

const int maxn = 120;
struct Edge
{
    int u, v;
    double cap,flow;
    Edge(int u, int v, double c, double f):u(u), v(v), cap(c), flow(f) {}
};

struct Dinic
{
    int n, m, s, t, cur[maxn];
    int d[maxn];
    bool vis[maxn];
    vector<Edge> edge;
    vector<int> G[maxn];
    void init(int n)
    {
        this->n=n;
        for(int i=0; i<=n; i++)
            G[i].clear();
        edge.clear();
    }
    int AddEdge(int u, int v, double c)
    {
        edge.push_back(Edge(u, v, c, 0));
        edge.push_back(Edge(v, u, 0, 0));
        m=edge.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
        return m-2;
    }
    bool bfs()
    {
        clr(vis, 0);
        queue<int> q;
        q.push(s);
        d[s]=0, vis[s]=1;
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=0; i<G[x].size(); i++)
            {
                Edge& e=edge[G[x][i]];
                if(!vis[e.v] && e.cap>e.flow)
                {
                    vis[e.v]=1;
                    d[e.v]=d[x]+1;
                    q.push(e.v);
                }
            }
        }
        return vis[t];
    }
    double dfs(int x, double a)
    {
        if(x==t || a<eps) return a;
        double flow=0, f;
        for(int& i=cur[x]; i<G[x].size(); i++)
        {
            Edge& e=edge[G[x][i]];
            if(d[x]+1==d[e.v] && (f=dfs(e.v, min(a, e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edge[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a<eps)break;
            }
        }
        return flow;
    }
    double MaxFlow(int s, int t)
    {
        this->s=s;
        this->t=t;
        double flow=0;
        while(bfs())
        {
            clr(cur, 0);
            flow+=dfs(s, oo);
        }
        return flow;
    }
} net;
int S,T;
int n,m,a[maxn],b[maxn],ma[maxn][maxn];
double all;
int judge(double te){
   net.init(T);
   rep1(i,1,n) net.AddEdge(m+i,T,(double)a[i]);
   rep1(i,1,m) rep1(j,1,n){
       int x=ma[i][j];
       if(x) net.AddEdge(i,m+j,(double)oo);
   }
   for(int i=1;i<=m;i++) net.AddEdge(S,i,te*b[i]);
   return fabs(net.MaxFlow(S,T)-all)<eps;
}
int main()
{
   scanf("%d %d",&n,&m);
   S = 0, T = n+m+1;
   net.init(T);  all=0;
   rep1(i,1,n) scanf("%d",&a[i]),all+=a[i];
   rep1(i,1,m) scanf("%d",&b[i]);
   rep1(i,1,m) rep1(j,1,n){
       int x; scanf("%d",&ma[i][j]);
   }
   double l = 0, r = 1e5;
   while(r - l > eps){
       double mid = (l+r)/2.0;
       if(judge(mid)) r = mid;
       else l = mid;
   }
   printf("%.6lf\n",l);
   return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值