• 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;
    }
  • 相关阅读:
    Linux Shell编程入门
    vim 文件在linux不换行,只显示^M解决办法
    服务器高性能程序 磁盘I/O篇
    车牌识别_转自别人的博客
    ubuntu网络简单设置
    C++设计模式(转载)
    结构算法之道
    C++设计模式工厂方法
    二叉树的深度优先遍历、广度优先遍历和非递归遍历
    iptables
  • 原文地址:https://www.cnblogs.com/captain1/p/9495470.html
Copyright © 2020-2023  润新知