• bzoj3280


    费用流

    建图:建立源汇s,t,对于每天建立两个点,live和dead,live向dead连接下界为a[i],上界为a[i],费用为0的边,表示一天需要只a[i]个人,也就是一天必须死a[i]个人,然后源点向第一天连上所有l[i],b[i],每天live连向下一天,容量为inf,费用为0,表示一天没有用过的研究生可以留到下一天,dead连向下一天的dead,表示可以不治疗死人,每天dead同时连向i+day[j]天,容量为inf,费用为q[j],表示可以治疗任意的死人去进行工作,然后跑一个可行流就行了,现在问题在于处理上下界的边,那么对于live和dead,我们把live连向t,表示流过live至少要有下界的流量,费用为0,s连向dead,表示至少有下界流量的流流入dead,费用为live到dead的费用,0,然后live向dead连一条容量为0的边,表示只能最多流过流量为0的流,这条边自然可以省略,然后就看最小费用,和流量是否为a[i]总和

    这里不用设立超级源汇是因为超级源汇的意义在于可以给任意点提供无限的流量,如果源汇本来就是提供流量而无其他意义,就不用设立了。上一题原来源点1是原图中的一部分,有自己的意义,所以需要额外的源汇,如果原来的源汇有下界流出或者有自己的意义就得设立新的源汇,否则不用

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 510, inf = 0x3f3f3f3f;
    struct edge {
        int nxt, to, f, c;
    } e[N * 50];
    int n, m, k, source, sink, tot, cnt = 1, sum;
    int a[N], head[N], d[N], pree[N], prev[N], vis[N], live[N], dead[N], day[N], c[N], l[N], p[N];
    inline void link(int u, int v, int f, int c)
    {
        e[++cnt].nxt = head[u];
        head[u] = cnt;
        e[cnt].f = f;
        e[cnt].to = v;
        e[cnt].c = c;
    }
    inline void insert(int u, int v, int f, int c)
    {
        link(u, v, f, c);
        link(v, u, 0, -c);
    }
    bool spfa()
    {
        memset(d, -1, sizeof(d));
        d[source] = 0;
        queue<int> q;
        q.push(source);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && (d[e[i].to] > d[u] + e[i].c || d[e[i].to] == -1))
            {
                pree[e[i].to] = i;
                prev[e[i].to] = u;
                d[e[i].to] = d[u] + e[i].c;
                if(vis[e[i].to] == 0)
                {
                    q.push(e[i].to);
                    vis[e[i].to] = 1;
                }
            }
        }
        return d[sink] != -1; 
    }
    inline int flow()
    {
        int ret = 0, ans = 0;
        while(spfa())
        {
            int now = sink, delta = inf;
            while(now != source)
            {
                delta = min(delta, e[pree[now]].f);
                now = prev[now];
            }
            now = sink;
            while(now != source)
            {
                e[pree[now]].f -= delta;
                e[pree[now] ^ 1].f += delta; 
                now = prev[now];
            }
            ret += delta;
            ans += delta * d[sink];
        }
        if(ret < sum) return -1;
        return ans;
    }
    inline void build()
    {
        //研究生 i = 1 -> m
        //天: m + 1 -> m + n 
        tot = 0;
        sink = 2 * n + m + 1; 
        for(int i = 1; i <= n; ++i) 
        {
            live[i] = ++tot;
            dead[i] = ++tot;
            insert(source, dead[i], a[i], 0);
            insert(live[i], sink, a[i], 0);
        }
        for(int i = 1; i <= m; ++i) insert(source, live[1], l[i], p[i]);
        for(int i = 1; i <= n; ++i)
        {
            if(i != n) 
            {
                insert(live[i], live[i + 1], inf, 0);
                insert(dead[i], dead[i + 1], inf, 0);
            }
            for(int j = 1; j <= k; ++j)
                if(i + day[j] + 1 <= n) 
                    insert(dead[i], live[i + day[j] + 1], inf, c[j]);
        }
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        for(int kase = 1; kase <= T; ++kase)
        {
            memset(head, 0, sizeof(head));
            cnt = 1;
            sum = 0;
            scanf("%d%d%d", &n, &m, &k);
            for(int i = 1; i <= n; ++i) 
            {
                scanf("%d", &a[i]);
                sum += a[i];
            }
            for(int i = 1; i <= m; ++i) scanf("%d%d", &l[i], &p[i]);
            for(int i = 1; i <= k; ++i) scanf("%d%d", &day[i], &c[i]);        
            build();
            int ans = flow();
            printf("Case %d: ", kase);
            if(ans == -1) puts("impossible");
            else printf("%d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    listview删除item
    标准listview加图标布局
    android事件消费机制,从外传到里面,里面具有优先选择权,如果里面的不需要,则传递给外面一层消费
    listview 按最新数据展示
    给listview添加数据,添加数据之后即刻显示出来,并把数据放在listview列表的最前面
    EditText限制输入长度和限定输入数字
    josn解析常见的几种方法
    bnu Robots on a grid
    hdu 1348 Wall
    hdu poj Oulipo
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7348840.html
Copyright © 2020-2023  润新知