[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\n" , ans);
        
        return 0;
    
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/10540066.html