[ZJOI2014] 璀璨光华(bfs建图 + dfs搜索)

problem

luogu-P3342

solution

你感觉这道题没考什么,又感觉考了什么

通过样例以及题面,我们并未获取到『立方体每个小方块的编号是按一定规则命名』的信息。

也就是说,我们需要通过输入的每个小方块相邻的编号的信息来建出这个立方体的坐标系。

我的做法较暴力但不用思考太多,简单易上手。你值得拥有

  • 首先,我们先随便找一个三度点(只有三个水晶和该水晶有公共面),钦定为 ( 1 , 1 , 1 ) (1,1,1) (1,1,1)

    然后以这个点 bfs \text{bfs} bfs 搜,得到每个点的距离,我们记为 d i s 0 dis_0 dis0

  • 其次,我们再随便找一个与上一个点距离恰好为 2 n − 2 2n-2 2n2 的点,即 d i s 0 ( i ) = 2 n − 2 dis_0(i)=2n-2 dis0(i)=2n2,钦定为 ( n , n , 1 ) (n,n,1) (n,n,1)

    然后以这个点 bfs \text{bfs} bfs 搜,得到每个点的距离,我们记为 d i s 1 dis_1 dis1

  • 接着,我们仍随便找一个与上两个点距离恰都为 n − 1 n-1 n1 的点,即 d i s 0 ( i ) = d i s 1 ( i ) = n − 1 dis_0(i)=dis_1(i)=n-1 dis0(i)=dis1(i)=n1,钦定为 ( n , 1 , 1 ) (n,1,1) (n,1,1)

    然后以这个点 bfs \text{bfs} bfs 搜,得到每个点的距离,我们记为 d i s 2 dis_2 dis2

这里的距离指的是曼哈顿距离 x , y , z x,y,z x,y,z 三维坐标差的绝对值之和。

考虑小方块 i i i 的距离信息点对 ( d i s 1 ( i ) − d i s 0 ( i ) , d i s 2 ( i ) − d i s 0 ( i ) ) \Big(dis_1(i)-dis_0(i),dis_2(i)-dis_0(i)\Big) (dis1(i)dis0(i),dis2(i)dis0(i))

observation1 : \text{observation1}: observation1: 该点对与 i i i 的真正的 z z z 坐标无关。

observation2 : \text{observation2}: observation2: 该点对与小方块的真正 ( x , y ) (x,y) (x,y) 坐标存在一一对应关系。这只能自己臆想了

在这里插入图片描述

d i s 0 ( i ) = ( x , y , z ) ↔ ( 1 , 1 , 1 ) dis_0(i)=(x,y,z)\leftrightarrow (1,1,1) dis0(i)=(x,y,z)(1,1,1),所以我们可以选择通过 d i s 0 ( i ) dis_0(i) dis0(i) 与已经求出的 x , y x,y x,y 来推出小方块的 z z z 坐标。

最后只用 dfs \text{dfs} dfs 暴搜枚举每个特殊发光小水晶扩散的方向, O ( 6 n ) O(6^n) O(6n)

然后 check \text{check} check 沿着该方向枚举一路上的水晶,用 v i s vis vis 标记是否已经访问过了,非第一次访问不计入发光贡献。

最后清空 vis \text{vis} vis 数组,也是按照方向清空。不然就是 O ( a 3 ) O(a^3) O(a3) 的复杂度了。

时间复杂度 O ( 6 n a ) O(6^na) O(6na)

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 400000
#define MAX 150
struct node { int x, y, z; }pos[MAX << 2][MAX << 2];
vector < int > G[maxn];
vector < node > NB;
int g[maxn], dir[maxn];
int dis[3][maxn];
int vis[MAX][MAX][MAX], val[MAX][MAX][MAX];
int Min = 1e9, Max = -1e9, n, m;
queue < int > q;

void bfs( int s, int *dis ) {
    dis[s] = 0; q.push( s );
    while( ! q.empty() ) {
        int u = q.front(); q.pop();
        for( int v : G[u] ) 
            if( dis[v] > dis[u] + 1 ) 
                dis[v] = dis[u] + 1, q.push( v );
    }
}

void calc() {
    int sum = 0;
    for( int k = 0;k < NB.size();k ++ ) {
        int x = NB[k].x, y = NB[k].y, z = NB[k].z;
        switch( dir[k] ) {
            case 0 : {
                for( int i = 1;i <= x;i ++ )
                    if( ! vis[i][y][z] )
                        vis[i][y][z] = 1, sum += val[i][y][z];
                break;
            }
            case 1 : {
                for( int i = x;i <= n;i ++ )
                    if( ! vis[i][y][z] )
                        vis[i][y][z] = 1, sum += val[i][y][z];
                break;
            }
            case 2 : {
                for( int i = 1;i <= y;i ++ )
                    if( ! vis[x][i][z] )
                        vis[x][i][z] = 1, sum += val[x][i][z];
                break;
            }
            case 3 : {
                for( int i = y;i <= n;i ++ )
                    if( ! vis[x][i][z] )
                        vis[x][i][z] = 1, sum += val[x][i][z];
                break;
            }
            case 4 : {
                for( int i = 1;i <= z;i ++ )
                    if( ! vis[x][y][i] )
                        vis[x][y][i] = 1, sum += val[x][y][i];
                break;
            }
            case 5 : {
                for( int i = z;i <= n;i ++ )
                    if( ! vis[x][y][i] )
                        vis[x][y][i] = 1, sum += val[x][y][i];
                break;
            }
        }
    }
    Min = min( Min, sum ), Max = max( Max, sum );
    for( int k = 0;k < NB.size();k ++ ) {
        int x = NB[k].x, y = NB[k].y, z = NB[k].z;
        switch( dir[k] ) {
            case 0 : for( int i = 1;i <= x;i ++ ) vis[i][y][z] = 0; break;
            case 1 : for( int i = x;i <= n;i ++ ) vis[i][y][z] = 0; break;
            case 2 : for( int i = 1;i <= y;i ++ ) vis[x][i][z] = 0; break;
            case 3 : for( int i = y;i <= n;i ++ ) vis[x][i][z] = 0; break;
            case 4 : for( int i = 1;i <= z;i ++ ) vis[x][y][i] = 0; break;
            case 5 : for( int i = z;i <= n;i ++ ) vis[x][y][i] = 0; break;
        }
    }
}

void dfs( int x ) {
    if( x == NB.size() ) return calc(), void();
    for( int i = 0;i < 6;i ++ ) dir[x] = i, dfs( x + 1 );
}

int CalcDis( int x, int y, int a, int b ) { return fabs( x - a ) + fabs( y - b ); }

int main() {
    memset( dis, 0x3f, sizeof( dis ) );
    scanf( "%d", &n );
    m = n * n * n;
    for( int i = 1, id;i <= m;i ++ ) {
        scanf( "%d", &g[i] );
        do { scanf( "%d", &id ), G[i].push_back( id ); } while( getchar() != '\n' );
    }
    int p1, p2, p3;
    for( int i = 1;i <= m;i ++ ) 
        if( G[i].size() == 3 ) 
            p1 = i;
    val[1][1][1] = g[p1]; bfs( p1, dis[0] );
    for( int i = 1;i <= m;i ++ ) 
        if( G[i].size() == 3 and dis[0][i] == (n - 1 << 1) ) 
            p2 = i;
    val[n][n][1] = g[p2]; bfs( p2, dis[1] );
    for( int i = 1;i <= m;i ++ ) 
        if( G[i].size() == 3 and dis[0][i] == n - 1 and dis[1][i] == n - 1 ) 
            p3 = i;
    val[n][1][1] = g[p3]; bfs( p3, dis[2] );
    for( int i = 1;i <= n;i ++ )
        for( int j = 1;j <= n;j ++ ) {
            int d0 = CalcDis( 1, 1, i, j );
            int d1 = CalcDis( n, n, i, j );
            int d2 = CalcDis( n, 1, i, j );
            pos[MAX + d1 - d0][MAX + d2 - d0] = { i, j, 1 };
        }
    for( int i = 1;i <= m;i ++ ) {
        node p = pos[MAX + dis[1][i] - dis[0][i]][MAX + dis[2][i] - dis[0][i]];
        p.z = dis[0][i] - CalcDis( 1, 1, p.x, p.y ) + 1;
        val[p.x][p.y][p.z] = g[i];
        if( ! g[i] ) NB.push_back( p );
    }
    dfs( 0 );
    printf( "%d %d\n", Min, Max );
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值