洛谷P3324 [SDOI2015]星际战争 题解

题目链接:

https://www.luogu.org/problemnew/show/P3324

分析:

因为本题的时间较多,不能枚举,但发现有单调性,于是二分答案,二分使用的时间TT

每个攻击装置造成的伤害总量已知,为TBiT*B_i,现在有了伤害总量、生命总量,如何判断在TT时间内,机器人是否被全部打死?

源点S向所有攻击装置连边,流量为TBiT*B_i

攻击装置向能攻击到的机器人连边,流量为INF

所有机器人向汇点T连边,流量为AiA_i

验证TT时间所有机器人都能被打死 当且仅当 上图的最大流=Ai= \sum A_i(所有机器人生命值之和)

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define maxn 110
#define inf 0x7fffffffffffffffll
using namespace std;
int n,m,s,t,d[maxn];
long long sum,ans,Sum_A;
long long a[maxn];
long long b[maxn];
int mp[maxn][maxn];
struct edge
{
    int to,rev;
    long long val;
    edge (int _to,long long _val,int _rev)
    {
        to=_to;
        val=_val;
        rev=_rev;
    }
};
vector<edge> e[maxn];
void add(int x,int y,long long val)
{
    e[x].push_back(edge(y,val,e[y].size()));
    e[y].push_back(edge(x,0,e[x].size()-1));
}
bool bfs()
{
    memset(d, -1, sizeof(d));
    queue<int> q;
    q.push(s);
    d[s]=0;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<e[x].size();i++)
        {
            int y=e[x][i].to;
            if(d[y]==-1 && e[x][i].val)
            {
                q.push(y);
                d[y]=d[x]+1;
            }
        }
    }
    if(d[t]==-1)
        return 0;
    else
        return 1;
}
long long dfs(int x,long long low) 
{
    if(x==t||low==0)
        return low;
    long long totflow=0;
    for(int i=0;i<e[x].size();i++)
    {
        int y=e[x][i].to;
        int rev=e[x][i].rev;
        if(d[y]==d[x]+1&&e[x][i].val) 
        {
            long long a=dfs(y,min(low,e[x][i].val)); 
            e[x][i].val-=a;
            e[y][rev].val+=a;
            low-=a;
            totflow+=a;
            if(low==0) 
                return totflow;
        }
    }
    if(low!=0) 
        d[x]=-1;
    return totflow;
}
bool pd(long long Time)
{
    for(int i=0;i<maxn;i++)
        e[i].clear();
    sum=ans=0;
    s=0,t=n+m+1;
    for(int i=1;i<=m;i++)
        add(s,i,Time*b[i]);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            if(mp[i][j])
                add(i,j+m,inf);
    for(int j=1;j<=n;j++)
        add(j+m,t,a[j]*10000);
    while(bfs())
    {
    	ans+=dfs(s,inf);
    }
    if(ans==Sum_A*10000)
        return 1;
    else
        return 0;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        Sum_A+=a[i];
    }
    for(int i=1;i<=m;i++)
        scanf("%lld",&b[i]);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&mp[i][j]);
    long long l=0,r=10000000000000ll;
    long long an=l;
    while(l<=r)
    {
        long long mid=(l+r)/2;
        if(pd(mid))
        {
            an=mid;
            r=mid-1;
        }
        else
            l=mid+1;
    }
    printf("%.6lf\n",(double)an/(double)10000.0);
    return 0;
}
posted @ 2019-04-19 20:15  ShineEternal  阅读(139)  评论(0编辑  收藏  举报