BZOJ 1976 BeiJing2010组队 能量魔方 Cube 最小割

题目大意

给出一个N×N×N的矩阵,矩阵上的每一个方块可以涂上两种颜色,相邻的两个方块如果涂上了不同的颜色,就会产生一点能量。现在已知了一些方块的颜色,问最多可以产生多少点能量。

思路

假设所有相邻的方块之间全部都产生能量,且不考虑已经上好色的方块,之后减去不合法的就行了。

一般来说这种相邻的方块之间会产生一些什么的一般都是把所有点染色,一种颜色的与S相连,另一种与T相连。这道题中,左侧的点若是最终属于S集,代表这个点上了P色,否则上了N色;右侧的点若是最终属于T集,代表这个点上了P色,否则上了N色。在最后的答案中,我们只记录P色周围有多少N色,而不讨论N色周围有多少P色。

因为现在我们假设的是所有的块之间都产生能量,所以先从S到所有左侧的点连上流量为这个点周围相邻的点的个数,右侧的点同理。如果一个点并不是P色,那么它就要失去所有的能量(因为只记录P色产生的能量)。

如果左边的点和右边的点不在同一个集合的话(也就是它们之间的边被割开了),那么他们最后的颜色就是相同的,因此不会产生能量,左侧和右侧各减1,所以这个边的流量就是2。

之后跑个Dinic就行了。。。

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 50
#define MAXP (MAX * MAX * MAX)
#define MAXE 1000010
#define INF 0x3f3f3f3f
#define S 0
#define T (MAXP - 1)
using namespace std;
#define INRANGE(x, y, z) (x * y * z && x <= m && y <= m && z <= m)
const int dx[] = {0, 1, -1, 0, 0, 0, 0};
const int dy[] = {0, 0, 0, 1, -1, 0, 0};
const int dz[] = {0, 0, 0, 0, 0, 1, -1};

struct MaxFlow{
    int head[MAXP], total;
    int next[MAXE], aim[MAXE], flow[MAXE];

    int deep[MAXP];

    MaxFlow():total(1) {}
    void Add(int x, int y, int f) {
        next[++total] = head[x];
        aim[total] = y;
        flow[total] = f;
        head[x] = total;
    }
    void Insert(int x, int y, int f) {
        Add(x, y, f);
        Add(y, x, 0);
    }
    bool BFS() {
        static queue<int> q;
        while(!q.empty())   q.pop();
        memset(deep, 0, sizeof(deep));
        deep[S] = 1;
        q.push(S);
        while(!q.empty()) {
            int x = q.front(); q.pop();
            for(int i = head[x]; i; i = next[i])
                if(flow[i] && !deep[aim[i]]) {
                    deep[aim[i]] = deep[x] + 1;
                    q.push(aim[i]);
                    if(aim[i] == T) return true;
                }
        }
        return false;
    }
    int Dinic(int x, int f) {
        if(x == T)  return f;
        int temp = f;
        for(int i = head[x]; i; i = next[i])
            if(flow[i] && deep[aim[i]] == deep[x] + 1 && temp) {
                int away = Dinic(aim[i], min(flow[i], temp));
                if(!away)   deep[aim[i]] = 0;
                flow[i] -= away;
                flow[i^1] += away;
                temp -= away;
            }
        return f - temp;
    }
}solver;

int m;
char src[MAX][MAX][MAX];
int num[MAX][MAX][MAX], cnt;

int ans;
int main()
{
    cin >> m;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%s", src[i][j] + 1);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            for(int k = 1; k <= m; ++k)
                num[i][j][k] = ++cnt;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            for(int k = 1; k <= m; ++k) {
                int near = 0;
                for(int d = 1; d <= 6; ++d) {
                    int fx = i + dx[d];
                    int fy = j + dy[d];
                    int fz = k + dz[d];
                    bool flag = INRANGE(fx, fy, fz);
                    near += flag;
                    if(flag && (i + j + k)&1)
                        solver.Insert(num[i][j][k], num[fx][fy][fz], 2);
                }
                ans += near;
                if((i + j + k)&1)
                    solver.Insert(S, num[i][j][k], near);
                else
                    solver.Insert(num[i][j][k], T, near);
            }
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            for(int k = 1; k <= m; ++k)
                if((i + j + k)&1) {
                    if(src[i][j][k] == ‘P‘)
                        solver.Insert(S, num[i][j][k], INF);
                    else if(src[i][j][k] == ‘N‘)
                        solver.Insert(num[i][j][k], T, INF);
                }
                else {
                    if(src[i][j][k] == ‘P‘)
                        solver.Insert(num[i][j][k], T, INF);
                    else if(src[i][j][k] == ‘N‘)
                        solver.Insert(S, num[i][j][k], INF);
                }
    int max_flow = 0;
    while(solver.BFS())
        max_flow += solver.Dinic(S, INF);
    cout << ans - max_flow << endl;
    return 0;
}
时间: 2024-07-31 14:20:25

BZOJ 1976 BeiJing2010组队 能量魔方 Cube 最小割的相关文章

【BZOJ1976】[BeiJing2010组队]能量魔方 Cube 最小割

[BZOJ1976][BeiJing2010组队]能量魔方 Cube Description 小C 有一个能量魔方,这个魔方可神奇了,只要按照特定方式,放入不同的 能量水晶,就可以产生巨大的能量. 能量魔方是一个 N*N*N 的立方体,一共用 N3 个空格可以填充能量水晶. 能量水晶有两种: ·一种是正能量水晶(Positive) ·一种是负能量水晶(Negative) 当这个魔方被填满后,就会依据填充的能量水晶间的关系产生巨大能量.对 于相邻两(相邻就是拥有同一个面)的两个格子,如果这两个格子

BZOJ1976: [BeiJing2010组队]能量魔方 Cube

1976: [BeiJing2010组队]能量魔方 Cube Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 832  Solved: 281[Submit][Status] Description 小C 有一个能量魔方,这个魔方可神奇了,只要按照特定方式,放入不同的 能量水晶,就可以产生巨大的能量. 能量魔方是一个 N*N*N 的立方体,一共用 N3 个空格可以填充能量水晶. 能量水晶有两种: ·一种是正能量水晶(Positive) ·一种是负能量

BZOJ 1976 能量魔方 Cube(最小割)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1976 题意:给出一个n*n*n的立方体.每个小单位为字母P或者字母N.相邻两个小单位字母不同则总价值加1.现在有些小单位的字母已经确定,合理安排其他小单位的字母使得总价值最大? 思路:显然,若所有小单位都未确定,则进 行黑白染色即PN相间的安排时价值最大.基于这样的考虑,我们将所有小单位分成黑白两种颜色,设为A和B.显然同一种颜色之间是不会相邻的.设S集合为A 集合中的P(就是已经给出

BZOJ 1934: [Shoi2007]Vote 善意的投票 最小割

1934: [Shoi2007]Vote 善意的投票 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1934 Description 幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉.对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神.虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票.我们定义一次投票的冲突数

BZOJ 1266 AHOI 2006 上学路线route 最小割

题目大意:给出一个无向图,问从1到n的最短路发生变化需要割掉最少花费的边权总值是多少. 思路:先要把所有最短路上的边搞出来,一个Floyd就可以解决,然后把所有在最短路上的边都加到最大流的图中,然后跑最小割就是答案. CODE: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 510

BZOJ 2965 保护古迹 平面图转对偶图+最小割

题目大意:给出一个平面图,这个平面图中分布着一些点,可以用平面图中的边将一些点围住,问围住k个点的最小花费是多少. 思路:这题重点是平面图转对偶图.做法不难理解.先将所有的边拆成两条,枚举所有的边,若这个边没有被标记过,那么就对这条边进行搜索,弄出来以这个边为一边的平面区域,可以顺时针或者逆时针.将所有边挂在这条边的起点上,在所有点上按照每条边的极角排序,每次找的时候找大于(或小于)当前边的反向边的第一条边作为搜索的下一条边.直到回到最开始的点.找边的过程中记录面积,判断面积的正负来判断这个平面

【BZOJ 3144】 3144: [Hnoi2013]切糕 (最小割模型)

3144: [Hnoi2013]切糕 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1764  Solved: 965 Description Input 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R). 100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超

BZOJ 1001 Beijing 2006 狼抓兔子 最小割

题目大意:有一张无向图,描述的是兔子窝的位置和之间的边.现在狼来抓兔子了,兔子慌忙的从(1,1)逃走到(m,n).每条边上都有能通过最多的兔子数量.狼不想让兔子逃走,每在一条边驻守一只狼就可以避免一个兔子通过.问最少多少狼可以让所有兔子都不能逃走. 思路:建图,按题目中的意思是去掉最小的边使得源到汇不连通,显然的最小割. CODE: #include <queue> #include <cstdio> #include <cstring> #include <io

BZOJ 1266 AHOI2006 上学路线route Floyd+最小割

题目大意:给定一张图,每条边有一个长度和一个花费,要求删掉一些边使1到n的最短路变长,求最小花销 首先求出最短路(用什么求随便,反正数据范围小),然后将所有在最短路上的边连到新图中,求最小割就是答案 图没有重边- - 数组开小WA了半篇- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 510 #define S 1 #defi