zoukankan      html  css  js  c++  java
  • [SHOI 2017] 寿司餐厅

    [题目链接]

             https://www.lydsy.com/JudgeOnline/problem.php?id=4873

    [算法]

            注意到题目中的限制条件可表述为 : 若选择区间[L , R] , 则必须选择区间[L + 1 , R]和[L , R - 1] , 这种依赖关系可以让我们联想到用最大权闭合子图解题

            将每种代号建一个点 , 每个区间同样建一个点

            首先将每个形如[i , i]的区间向其代号连边 

            然后将每个区间[L , R]所代表的点向[L + 1 , R]和[L , R - 1]连边

            注意我们需要减去代价mx ^ 2 + cx

            那么我们将每个形如[i , i]的区间所代表点的点权减去其代号 , 将每种代号i所代表点的点权减去m * i ^ 2

            时间复杂度 : O(Dinic(N ^ 2 , N ^ 2)) 

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int N = 110;
    const int inf = 2e9;
    
    struct edge
    {
            int to , w , nxt;
    } e[N * N * 10];
    
    int n , m , cnt , mx , S , T , tot;
    int d[N][N] , a[N * 10] , point[N][N] , head[N * N * 10] , dep[N * N * 10];
    
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void addedge(int u , int v , int w)
    {
            ++tot;
            e[tot] = (edge){v , w , head[u]};
            head[u] = tot;
            ++tot;
            e[tot] = (edge){u , 0 , head[v]};
            head[v] = tot;
    }
    inline bool bfs()
    {
            queue< int > q;
            for (int i = 1; i <= T; ++i)
                    dep[i] = -1;
            q.push(S);
            dep[S] = 1;
            while (!q.empty())
            {
                    int cur = q.front();
                    q.pop();
                    for (int i = head[cur]; i; i = e[i].nxt)
                    {
                            int v = e[i].to , w = e[i].w;
                            if (w > 0 && dep[v] == -1)
                            {
                                    dep[v] = dep[cur] + 1;
                                    q.push(v);
                                    if (v == T) return true;
                            }
                    }        
            }        
            return false;
    }
    inline int dinic(int u , int flow)
    {
            int k , rest = flow;
            if (u == T)
                    return flow;
            for (int i = head[u]; i && rest; i = e[i].nxt)
            {
                    int v = e[i].to , w = e[i].w;
                    if (w > 0 && dep[v] == dep[u] + 1)
                    {
                            k = dinic(v , min(rest , w));
                            e[i].w -= k;
                            e[i ^ 1].w += k;
                            if (!k) dep[v] = 0;
                            rest -= k;
                    }
            }
            return flow - rest;
    }
    
    int main()
    {
            
            read(n); read(m);
            tot = 1;
            for (int i = 1; i <= n; ++i) 
            {
                    read(a[i]);
                    mx = max(mx , a[i]);
            }
            cnt = mx;
            for (int i = 1; i <= n; ++i)
            {
                    for (int j = i; j <= n; ++j)
                    {
                            read(d[i][j]);
                            point[i][j] = ++cnt;
                    }
            }
            S = cnt + 1 , T = S + 1;
            int ans = 0;
            for (int i = 1; i <= n; ++i) d[i][i] -= a[i];
            for (int i = 1; i <= mx; ++i) addedge(i , T , m * i * i);
            for (int i = 1; i <= n; i++) addedge(point[i][i] , a[i] , inf);
            for (int i = 1; i <= n; ++i)
            {
                    for (int j = i; j <= n; ++j)
                    {
                            if (i <= j - 1)
                                    addedge(point[i][j] , point[i][j - 1] , inf);
                            if (i + 1 <= j)
                                    addedge(point[i][j] , point[i + 1][j] , inf);
                            if (d[i][j] >= 0)
                            {
                                    ans += d[i][j];
                                    addedge(S    , point[i][j] , d[i][j]);
                            } else addedge(point[i][j] , T , -d[i][j]);
                    }
            }
            while (bfs())
            {
                    while (int flow = dinic(S , inf))
                            ans -= flow;
            }
            printf("%d
    " , ans);
            
            return 0;
        
    }
  • 相关阅读:
    Linux 多线程环境下 进程线程终止函数小结
    C++:vector中的resize()函数 VS reserve()函数
    Linux进程间通信之信号量(semaphore)、消息队列(Message Queue)和共享内存(Share Memory)
    Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
    求全与求专
    wpf \silverlight 保存控件为图片
    软件版本号详解(转)
    WPF 自定义快捷键命令(Command)(转)
    WIN2003系统远程桌面多连接数设置终极大法
    程序集强命名与GAC
  • 原文地址:https://www.cnblogs.com/evenbao/p/10540066.html
Copyright © 2011-2022 走看看