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
    */
    
    
  • 相关阅读:
    面向对象设计大作业第二阶段:图书馆系统
    OO之接口-DAO模式代码阅读及应用
    OO设计-有理数类的设计
    DS博客作业05--查找
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS01——线性表
    c博客06-结构体&文件
    C语言博客作业05——指针
  • 原文地址:https://www.cnblogs.com/mollnn/p/13382016.html
Copyright © 2011-2022 走看看