zoukankan      html  css  js  c++  java
  • Codeforces 863F

    863F - Almost Permutation

    题意

    给出每个位置可以放的数字的范围,定义 (cost = sum_{i=1}^{n}(cnt(i))^2) ,其中 (cnt(i)) 为数字 (i) ((1 leq i leq n)) 出现的次数。将每个位置都填上一个数字,求 (cost) 的最小值。

    分析

    没想到可以用网络流去解决这道问题。本题属于最小费用最大流问题。
    对于每个代表数字的结点,从源点都要连 (n) 条边,费用为(1, 3, 5,..., 2*k-1),前缀和正好对应某个数字取 (k) 次时的花费。根据位置和可以放的数字之间的对应关系连边,费用为 (0) ,所有代表位置的结点连边到汇点,费用为 (0)。以上每条边的容量都为 (1) 。跑一下费用流的模板即可。

    思维好题啊。

    code

    #include<bits/stdc++.h>
    #define l first
    #define r second
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> P;
    const int MAXN = 1005; //
    const int MAXM = 10005; // 注意扩张的边的数量
    const int INF = 0x3f3f3f3f;
    struct Edge {
        int to, next, cap, flow, cost;
    } edge[MAXM * 4];
    int head[MAXN], tol;
    int pre[MAXN], dis[MAXN];
    bool vis[MAXN];
    int N;//节点总个数,节点编号从0~N-1
    void init(int n) {
        N = n;
        tol = 0;
        memset(head, -1, sizeof head);
        memset(pre, 0, sizeof pre);
        memset(dis, 0, sizeof dis);
        memset(vis, 0, sizeof vis);
        memset(edge, 0, sizeof edge);
    }
    void addedge (int u, int v, int cap, int cost) {
        edge[tol] = Edge{v, head[u], cap, 0, cost};
        head[u] = tol++;
        edge[tol] = Edge{u, head[v], 0, 0, -cost};
        head[v] = tol++;
    }
    bool spfa(int s, int t) {
        queue<int>q;
        for(int i = 0; i < N; i++) {
            dis[i] = INF;
            vis[i] = false;
            pre[i] = -1;
        }
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i]. to;
                if(edge[i].cap > edge[i].flow &&
                        dis[v] > dis[u] + edge[i].cost) {
                    dis[v] = dis[u] + edge[i].cost;
                    pre[v] = i;
                    if(!vis[v]) {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t] == -1) return false;
        else return true;
    }
    //返回的是最大流,cost存的是最小费用
    int minCostMaxflow(int s, int t, int &cost) {
        int flow = 0;
        cost = 0;
        while(spfa(s,t)) {
            int Min = INF;
            for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
                if(Min > edge[i].cap - edge[i]. flow)
                    Min = edge[i].cap - edge[i].flow;
            }
            for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) {
                edge[i].flow += Min;
                edge[i^1].flow -= Min;
                cost += edge[i].cost * Min;
            }
            flow += Min;
        }
        return flow;
    }
    P a[110];
    int main() {
        int n, q;
        cin >> n >> q;
        for(int i = 1; i <= n; i++) {
            a[i].l = 1;
            a[i].r = n;
        }
        int flg = 0;
        while(q--) {
            int op, l, r, v;
            cin >> op >> l >> r >> v;
            for(int i = l; i <= r; i++) {
                if(op == 1) {
                    a[i].l = max(a[i].l, v);
                } else {
                    a[i].r = min(a[i].r, v);
                }
                if(a[i].l > a[i].r) {
                    flg = 1;
                    break;
                }
            }
        }
        init(2 * n + 2);
        int s = 0, t = 2 * n + 1;
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= n; j++) { // 源点向每个代表数字的结点连 n 条边
                addedge(s, i, 1, 1 + 2 * (j - 1));
            }
            for(int j = a[i].l; j <= a[i].r; j++) { // 根据数字和位置的对应关系连边
                addedge(j, i + n, 1, 0);
            }
            addedge(i + n, t, 1, 0); // 代表位置的结点向汇点连边
        }
        int cost = 0;
        int flow = minCostMaxflow(s, t, cost);
        if(flow != n) cost = -1;
        cout << cost << endl;
    }
    
  • 相关阅读:
    常见的HTTP状态码有哪些?
    使用Hbuild打包APP
    Android APK反编译
    小程序|页面跳转的方法
    vi/vim 命令
    webpack学习笔记
    egg框架学习笔记
    IOS弹出系统键盘后,页面不恢复
    js上传文件
    webpack学习笔记
  • 原文地址:https://www.cnblogs.com/ftae/p/7614536.html
Copyright © 2011-2022 走看看