zoukankan      html  css  js  c++  java
  • 2020杭电多校第二场 E

    Description

    工厂中有 (n) 个工人,(m) 个设备,第 (i) 个工人匹配第 (j) 号设备的代价是 (a_i j^2 + b_i j + c_i)

    每个工人和设备至多只能参与一次匹配

    对每一个 (k in [1,n]),求形成 (k) 对匹配的最小代价。

    Solution

    对于每个二次函数,其最小值点唯一,显然这个工人取的一定是二次函数前 (n) 小的整点

    于是每个工人向前 (n) 小的位置连边,即可建出一张点数边数均为 (O(n^2)) 的费用流图

    增广 (n) 次找到流量为 (1,2,3,...,n) 的费用流即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1005;
    
    namespace flow {
    const int N = 100005;
    const int M = 1000005;
    const int inf = 1e+12;
    struct Edge {
        int p, c, w, nxt = -1;
    } e[N];
    int s, t, tans, ans, cost, ind, bus[N], qhead = 0, qtail = -1, qu[M],vis[N], dist[N];
    
    void graph_link(int p, int q, int c, int w) {
        e[ind].p = q;
        e[ind].c = c;
        e[ind].w = w;
        e[ind].nxt = bus[p];
        bus[p] = ind;
        ++ind;
    }
    void make(int p, int q, int c, int w) {
        graph_link(p, q, c, w);
        graph_link(q, p, 0, -w);
    }
    int dinic_spfa() {
        qhead = 0;
        qtail = -1;
        memset(vis, 0x00, sizeof vis);
        memset(dist, 0x3f, sizeof dist);
        vis[s] = 1;
        dist[s] = 0;
        qu[++qtail] = s;
        while (qtail >= qhead) {
            int p = qu[qhead++];
            vis[p] = 0;
            for (int i = bus[p]; i != -1; i = e[i].nxt)
                if (dist[e[i].p] > dist[p] + e[i].w && e[i].c > 0) {
                    dist[e[i].p] = dist[p] + e[i].w;
                    if (vis[e[i].p] == 0)
                        vis[e[i].p] = 1, qu[++qtail] = e[i].p;
                }
        }
        return dist[t] < inf;
    }
    int dinic_dfs(int p, int lim) {
        if (p == t)
            return lim;
        vis[p] = 1;
        int ret = 0;
        for (int i = bus[p]; i != -1; i = e[i].nxt) {
            int q = e[i].p;
            if (e[i].c > 0 && dist[q] == dist[p] + e[i].w && vis[q] == 0) {
                int res = dinic_dfs(q, min(lim, e[i].c));
                cost += res * e[i].w;
                e[i].c -= res;
                e[i ^ 1].c += res;
                ret += res;
                lim -= res;
                if (lim == 0)
                    break;
            }
        }
        return ret;
    }
    void solve(int _s,int _t,int times) {
        s=10003; t=_t;
        ans = 0;
        cost = 0;
        for(int i=1;i<=times;i++) {
            make(s,10001,1,0);
            dinic_spfa();
            memset(vis, 0x00, sizeof vis);
            ans += dinic_dfs(s, inf);
            cout<<cost<<(i==times?"":" ");
        }
        cout<<endl;
    }
    void init() {
        memset(bus, 0xff, sizeof bus);
        ind=0;
    }
    }
    
    //// Main
    
    struct network_edge
    {
        int u,v,w,c;
    };
    
    vector <network_edge> network_edges;
    
    void make(int u,int v,int w,int c)
    {
        network_edges.push_back({u,v,w,c});
    }
    
    void network_print()
    {
        for(auto p:network_edges)
        {
            cout<<p.u<<","<<p.v<<"  "<<p.w<<"  "<<p.c<<endl;
        }
    }
    
    void network_transfer()
    {
        for(auto p:network_edges)
        {
            flow::make(p.u,p.v,p.w,p.c);
        }
    }
    
    struct equip
    {
        int a,b,c;
    } equipment[N];
    
    int n,m;
    
    void clean()
    {
        network_edges.clear();
        flow::init();
    }
    
    const int S = 10001;
    const int T = 10002;
    
    void load()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            equip &e=equipment[i];
            cin>>e.a>>e.b>>e.c;
        }
    }
    
    int get_minpoint(int a,int b,int c)
    {
        return -b/(2*a);
    }
    
    void build_network()
    {
        map <int,int> mp;
    
        for(int i=1;i<=n;i++)
        {
            equip &e=equipment[i];
            int p=get_minpoint(e.a,e.b,e.c);
    
            p=min(p,m);
            p=max(p,1ll);
    
            int low=max(1ll,p-n-1);
            int high=min(m,p+n+1);
    
            for(int j=low;j<=high;j++)
            {
                mp[j]++;
            }
        }
    
        int ind=0;
        for(auto &pr:mp)
        {
            pr.second=++ind;
        }
    
        for(int i=1;i<=n;i++)
        {
            equip &e=equipment[i];
            int p=get_minpoint(e.a,e.b,e.c);
    
            p=min(p,m);
            p=max(p,1ll);
    
            int low=max(1ll,p-n-1);
            int high=min(m,p+n+1);
    
            for(int j=low;j<=high;j++)
            {
                make(i,1000+mp[j],1,e.a*j*j+e.b*j+e.c);
            }
        }
    
        for(int i=1;i<=n;i++)
        {
            make(S,i,1,0);
        }
    
        for(int i=1;i<=ind;i++)
        {
            make(1000+i,T,1,0);
        }
    }
    
    void solve()
    {
        flow::solve(S,T,n);
    }
    
    void work()
    {
        clean();
        load();
        build_network();
        //network_print();
        network_transfer();
        solve();
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        int t;
        cin>>t;
        while(t--)
        {
            work();
        }
    }
    
    /*
    2
    3 5
    2 3 10
    2 -3 10
    1 -1 4
    3 5
    2 3 10
    2 -3 10
    1 -1 4
    */
    
    
  • 相关阅读:
    [LeetCode 1029] Two City Scheduling
    POJ 2342 Anniversary party (树形DP入门)
    Nowcoder 106 C.Professional Manager(统计并查集的个数)
    2018 GDCPC 省赛总结
    CF 977 F. Consecutive Subsequence
    Uva 12325 Zombie's Treasure Chest (贪心,分类讨论)
    Poj 2337 Catenyms(有向图DFS求欧拉通路)
    POJ 1236 Network of Schools (强连通分量缩点求度数)
    POJ 1144 Network (求割点)
    POJ 3310 Caterpillar(图的度的判定)
  • 原文地址:https://www.cnblogs.com/mollnn/p/13382016.html
Copyright © 2011-2022 走看看