SDOI2015 星际战争

Posted captain1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2015 星际战争相关的知识,希望对你有一定的参考价值。

题目传送门

这道题的m,n都非常的小,之后又看到……武器是可以连续攻击的,于是初步想到了网络流。

想到这道题是网络流之后,就很自然的想到应该在武器与机器人之间建边,在源点和武器之间建边,在机器人和汇点之间建边。

不过应该怎么建呢?我们知道武器可以连续攻击,就可以把武器的攻击看做水流,那么很显然,武器的攻击力乘以攻击的时间是武器一侧的流量限制,而机器人的生命值是机器人一侧的流量限制,而在武器和机器人之间没有流量限制,直接建容量为INF的边就可以了,因为前面原点一侧已经对其流量限制过了。

时间是我们要求的,所以我们可以进行二分答案,每次在二分的基础上建边,之后直接跑网络流,如果最大流等于机器人生命值之和说明跑完了,否则没跑完,这样二分即可。

注意因为精度要求是10^-4,所以可以直接把时间和机器人生命扩大10000倍,之后直接解决即可。

还有就是二分上界不要设的和INF一样大,否则会wa。

看一下代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<set>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘
‘)
using namespace std;
typedef long long ll;
const ll INF = 1e17;
const int M = 40005;

ll read()
{
    ll ans = 0,op = 1;
    char ch = getchar();
    while(ch < 0 || ch > 9)
    {
        if(ch == -) op = -1;
        ch = getchar();
    }
    while(ch >= 0 && ch <= 9)
    {
        ans *= 10;
        ans += ch - 0;
        ch = getchar();
    }
    return ans * op;
}
struct node
{
    ll next,to,v;
} e[M];
ll deep[M],ecnt = -1,l,r = 1e16,n,m,a[M],b[M],g[60][60],mid;
ll source = 199,sink = 200,cnt,head[M],maxflow,curr,cur[M];
queue <int> q;
void clear()
{
    memset(e,0,sizeof(e));
    memset(head,-1,sizeof(head));
    memset(cur,0,sizeof(cur));
    ecnt = -1,cnt = 0,maxflow = 0,curr = 0;
}
void add(ll x,ll y,ll z)
{
    e[++ecnt].to = y;
    e[ecnt].v = z;
    e[ecnt].next = head[x];
    head[x] = ecnt;
}
void build()
{
    clear();
    rep(i,1,m) add(source,++cnt,mid * b[i]),add(cnt,source,0);
    rep(i,1,n) add(++cnt,sink,a[i] * 10000),add(sink,cnt,0),curr += a[i] * 10000;
    rep(i,1,m)
    rep(j,1,n)
    if(g[i][j]) add(i,j+m,INF),add(j+m,i,0);
}
bool bfs(ll s,ll t)
{
    memset(deep,-1,sizeof(deep));
    while(!q.empty()) q.pop();
    rep(i,1,cnt) cur[i] = head[i];
    cur[source] = head[source],cur[sink] = head[sink];
    deep[s] = 0,q.push(s);
    while(!q.empty())
    {
        ll k = q.front();
        q.pop();
        for(int i = head[k]; i != -1; i = e[i].next)
        {
            if(deep[e[i].to] == -1 && e[i].v)
            {
                deep[e[i].to] = deep[k] + 1;
                q.push(e[i].to);
            }
        }
    }
    if(deep[t] != -1) return 1;
    else return 0;
}
ll dfs(ll s,ll t,ll limit)
{
    if(!limit || s == t) return limit;
    for(int i = cur[s]; i != -1; i = e[i].next)
    {
        cur[s] = i;
        if(deep[e[i].to] != deep[s] + 1) continue;
        ll f = dfs(e[i].to,t,min(limit,e[i].v));
        if(f)
        {
            e[i].v -= f,e[i^1].v += f;
            return f;
        }
    }
    return 0;
}
bool dinic(ll s,ll t)
{
    while(bfs(s,t)) maxflow += dfs(s,t,INF);
    if(maxflow == curr) return 1;
    else return 0;
}
int main()
{
    n = read(),m = read();
    rep(i,1,n) a[i] = read();
    rep(i,1,m) b[i] = read();
    rep(i,1,m)
    rep(j,1,n) g[i][j] = read();
    while(l < r)
    {
        mid = l + r >> 1;
        build();
        if(dinic(source,sink)) r = mid;
        else l = mid + 1;
    }
    printf("%.6lf
",(double)l / 10000.0);
    return 0;
}

 

以上是关于SDOI2015 星际战争的主要内容,如果未能解决你的问题,请参考以下文章

[SDOI2015]星际战争

BZOJ 3993 [SDOI2015]星际战争

BZOJ3993[SDOI2015]星际战争 二分+最大流

SDOI2015第1轮第2试星际战争

luogu P3324 [SDOI2015]星际战争

SDOI2015 星际战争