bzoj3619: [Zjoi2014]璀灿光华

题目
题解

题解:

首先确定一个原点(度数为3),然后从点BFS,计算到每个点经过的点的个数,我们发现,度数为3而且与原点有2n−1个点的点,是和原点在同一个平面而且是原点对角线上的另一个点
这样的点一共有3个,每一个和原点都能确定所有点的一个维度,只要对它进行BFS,然后若一个点到原点是 S[i] S [ i ] ,到关键点是 T[i] T [ i ] ,那么该维度就是 (S[i]+T[i]2n)/2+1 ( S [ i ] + T [ i ] − 2 n ) / 2 + 1
于是我们做3遍就可以确定所有点的坐标了
注意:照亮是照亮一整行或一整列,而不是照亮一个格子,我刚开始题意理解错了,希望没人犯这种错误

标程:

#include<bits/stdc++.h>
using namespace std;
const int M=343002;
struct node{
    int to,ne;
}e[M*6];
int g[M],a[9],S[M],T[M],f[71][71][71],vis[71][71][71],p[M][3],h[M],tot,cnt,sz[M],mn,mx,end,q[M],n,m,rt,sum,i,x,
b[6][3]={{0,0,1},{0,0,-1},{0,1,0},{0,-1,0},{1,0,0},{-1,0,0}};
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
    end=0;int x=0;char ch=gc();
    for (;ch<48||ch>57;ch=gc())if(ch=='\n')return -1;
    for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
    if (ch=='\n') end=1;
    return x;
}
inline void add(int x,int y){
    e[++tot]=(node){y,h[x]};
    h[x]=tot;
}
inline void bfs(int s,int *d){
    int he=0,ta=1;
    memset(d,0,(m+1)<<2);
    q[0]=s;d[s]=1;
    while (he<ta){
        int u=q[he++];
        for (int i=h[u],v;i;i=e[i].ne)
            if (!d[v=e[i].to]) d[v]=d[u]+1,q[ta++]=v;
    }
}
inline void calc(int u,int w){
    bfs(u,T);
    for (int i=1;i<=m;i++) p[i][w]=(S[i]+T[i]-2*n)/2+1;
}
inline void build(){
    bfs(rt,S);int w=0;
    for (int i=1;i<=m;i++)
        if (sz[i]==3 && S[i]==2*n-1) calc(i,w++);
    for (int i=1;i<=m;i++) f[p[i][0]][p[i][1]][p[i][2]]=i;
}
inline void add(int x,int y,int z,int d){
    while (1){
        if (!x || x>n || !y || y>n || !z || z>n) return;
        if (!(vis[x][y][z]++)) sum+=g[f[x][y][z]];
        x+=b[d][0],y+=b[d][1],z+=b[d][2];
    }
}
inline void clear(int x,int y,int z,int d){
    while (1){
        if (!x || x>n || !y || y>n || !z || z>n) return;
        if (!(--vis[x][y][z])) sum-=g[f[x][y][z]];
        x+=b[d][0],y+=b[d][1],z+=b[d][2];
    }
}
inline void dfs(int st){
    if (st==cnt){
        if (sum<mn) mn=sum;
        if (sum>mx) mx=sum;
        return;
    }
    int x=p[a[st]][0],y=p[a[st]][1],z=p[a[st]][2];
    for (int i=0;i<6;i++){
        add(x,y,z,i);
        dfs(st+1);
        clear(x,y,z,i);
    }
}
int main(){
    scanf("%d",&n);m=n*n*n;
    for (i=1;i<=m;i++){
        scanf("%d",&g[i]);
        if (!g[i]) a[cnt++]=i;
        while (1){
            x=read();
            if (x==-1) break;
            add(i,x);sz[i]++;
            if (end) break;
        }
        if (sz[i]==3) rt=i;
    }
    build();
    mn=1e9;dfs(0);
    printf("%d %d",mn,mx);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值