• [BZOJ 1475] 方格取数


    [题目链接]

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

    [算法]

             首先将方格黑白染色 , 也就是说 , 如果(i + j)为奇数 , 这个点就是黑点 , 否则是白点

             那么这个n * n的方格就被分为了两个集合 , 一个是黑点集合 , 一个是白点集合

             如果选取一个黑点 , 造成影响的是四方向内的白点

             如果选取一个白点 , 造成影响的是四方向内的黑点

             考虑首先选取所有的点 , 然后去掉最小代价的点 , 并使方案合法

             那么这就是一个最小割的经典模型 :

              将源点向所有黑点连流量为权值的边

              将所有白点向汇点连流量为权值的边

              将所有黑点向四方向内的白点连流量为正无穷的边

              求解这个图的最小割即可

              时间复杂度 : O(dinic(N , M))

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    #define N 110
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int inf = 1e9;
    const int dx[4] = {0 , 0 , -1 , 1};
    const int dy[4] = {-1 , 1 , 0 , 0};
    
    struct edge
    {
        int to , w , nxt;
    } e[N * N * 2];
    
    int n , m , S , T , tot;
    int a[N][N];
    int dep[N * N] , head[N * N];
    
    template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
    template <typename T> inline void chkmax(T &x , T y) { x = max(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 bool bfs(int s)
    {
        queue< int > q;
        q.push(s);
        memset(dep , 255 , sizeof(dep));
        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 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 (dep[v] == dep[u] + 1 && w > 0)
            {
                int k = dinic(v , min(w , rest));
                if (!k) dep[v] = 0;
                rest -= k;
                e[i].w -= k;
                e[i ^ 1].w += k;
            }
        }
        return flow - rest;
    }
    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 valid(int x , int y)
    {
        return x >= 1 && x <= m && y >= 1 && y <= n;
    }
    
    int main()
    {
        
        read(m); n = m;
        int cnt = 0;
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                read(a[i][j]);
                cnt += a[i][j]; 
            }
        }
        S = n * m + 1 , T = S + 1;
        tot = 1;
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if ((i + j) & 1)
                    addedge(S , (i - 1) * n + j , a[i][j]);
                else addedge((i - 1) * n + j , T , a[i][j]);
            }
        }
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                for (int k = 0; k < 4; k++)
                {
                    int x = i + dx[k] , y = j + dy[k];
                    if (valid(x , y) && (i + j) & 1)
                        addedge((i - 1) * n + j , (x - 1) * n + y , inf);
                }
            }
        }
        int ans = 0;
        while (bfs(S))
        {
            while (int flow = dinic(S , inf)) ans += flow; 
        }
        printf("%d
    " , cnt - ans);
        
        return 0;
    }
  • 相关阅读:
    程序员必看书籍(转载)
    JBPM的ORACLE脚本
    XFire构建web service客户端的五种方式
    为什么中国出不了facebook和Twitter?
    用dwr封装表单项提交表单
    Java 程序员容易犯的10个SQL错误
    SQL语句优化方法30例
    sqlserver sql语句查看分区记录数、查看记录所在分区
    SQL Case when 的使用方法
    sqlserver sql语句附加 分离数据库
  • 原文地址:https://www.cnblogs.com/evenbao/p/10355647.html
Copyright © 2020-2023  润新知