习题:星际战争(网络流)

题目

传送门

思路

如果正向思考直接求出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;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/12025360.html