• 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
    */
    
    
  • 相关阅读:
    MVC模式-----struts2框架(2)
    MVC模式-----struts2框架
    html的<h>标签
    jsp脚本元素
    LeetCode "Paint House"
    LeetCode "Longest Substring with At Most Two Distinct Characters"
    LeetCode "Graph Valid Tree"
    LeetCode "Shortest Word Distance"
    LeetCode "Verify Preorder Sequence in Binary Search Tree"
    LeetCode "Binary Tree Upside Down"
  • 原文地址:https://www.cnblogs.com/mollnn/p/13382016.html
Copyright © 2020-2023  润新知