zoukankan      html  css  js  c++  java
  • 【bzoj1475】方格取数 网络流最小割

    题目描述

    在一个n*n的方格里,每个格子里都有一个正整数。从中取出若干数,使得任意两个取出的数所在格子没有公共边,且取出的数的总和尽量大。

    输入

    第一行一个数n;(n<=30) 接下来n行每行n个数描述一个方阵

    输出

    仅一个数,即最大和

    样例输入

    2
    1 2
    3 5

    样例输出

    6


    题解

    网络流最小割

    将原图黑白染色,分别和源点和汇点连边,容量为原数;相邻的点连边,容量为inf。

    答案为sum-mincut。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define N 1000
    #define M 10000
    #define inf 0x7fffffff
    #define pos(i , j) (i - 1) * n + j
    using namespace std;
    queue<int> q;
    int map[35][35] , head[N] , to[M] , val[M] , next[M] , cnt = 1 , s , t , dis[N];
    void add(int x , int y , int z)
    {
        to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
        to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
    }
    bool bfs()
    {
        int x , i;
        memset(dis , 0 , sizeof(dis));
        while(!q.empty()) q.pop();
        dis[s] = 1 , q.push(s);
        while(!q.empty())
        {
            x = q.front() , q.pop();
            for(i = head[x] ; i ; i = next[i])
            {
                if(val[i] && !dis[to[i]])
                {
                    dis[to[i]] = dis[x] + 1;
                    if(to[i] == t) return 1;
                    q.push(to[i]);
                }
            }
        }
        return 0;
    }
    int dinic(int x , int low)
    {
        if(x == t) return low;
        int temp = low , i , k;
        for(i = head[x] ; i ; i = next[i])
        {
            if(val[i] && dis[to[i]] == dis[x] + 1)
            {
                k = dinic(to[i] , min(temp , val[i]));
                if(!k) dis[to[i]] = 0;
                val[i] -= k , val[i ^ 1] += k;
                if(!(temp -= k)) break;
            }
        }
        return low - temp;
    }
    int main()
    {
        int n , i , j , sum = 0;
        scanf("%d" , &n) , s = 0 , t = n * n + 1;
        for(i = 1 ; i <= n ; i ++ )
            for(j = 1 ; j <= n ; j ++ )
                scanf("%d" , &map[i][j]) , sum += map[i][j];
        for(i = 1 ; i <= n ; i ++ )
        {
            for(j = 1 ; j <= n ; j ++ )
            {
                if((i + j) % 2 == 0)
                {
                    add(s , pos(i , j) , map[i][j]);
                    if(i > 1) add(pos(i , j) , pos(i - 1 , j) , inf);
                    if(i < n) add(pos(i , j) , pos(i + 1 , j) , inf);
                    if(j > 1) add(pos(i , j) , pos(i , j - 1) , inf);
                    if(j < n) add(pos(i , j) , pos(i , j + 1) , inf);
                }
                else add(pos(i , j) , t , map[i][j]);
            }
        }
        while(bfs()) sum -= dinic(s , inf);
        printf("%d
    " , sum);
        return 0;
    }
    

     

  • 相关阅读:
    Codeblocks的常用Debug快捷键
    大整数乘法(POJ2389)
    简单深搜
    Windows安装时的几个命令(摘录)
    模拟栈的回溯,完全二叉树搜索,(ZOJ1004)
    生理周期,POJ(1006)
    next_permutation,POJ(1256)
    计算次数,POJ(1207)
    模拟,找次品硬币,Counterfeit Dollar(POJ 1013)
    深搜(DFS),Image Perimeters
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6950345.html
Copyright © 2011-2022 走看看