原题链接

OJ 题号
洛谷 3342
loj 2203
bzoj 3619

题目描述

金先生有一个女朋友没名字。她勤劳勇敢、智慧善良。金先生很喜欢她。为此,金先生用\(a^3\)块\(1 \times 1 \times 1\)的独特的水晶制作了一个边长为\(a\)的水晶立方体,他要将这个水晶立方体送给他见过最单纯善良的她。

由于水晶立方体太太,不好运送,金先生还是将它拆开来送出。他相信拼好这个水晶立方难不倒聪明的她。

没名字收到了礼物后果然不一会儿就根据说明将水晶立方体拼好了。没名字发现,有\(n\)块水晶在漆黑安静的夜晚会随机以等概率向上下左右前后六个方向的一个发出光。被光照到的水晶显得格外好看。没名字给每一块不会发光的水晶定义了一个好看程度。水晶立方体在夜晚中的好看程度就是每块被光照到的水晶的好看程度之和。没名字想知道,水晶立方体在夜晚中的好看程度的最小值和最大值。

输入格式

第一行是 \(a\),表示水晶立方体的边长。

接下来 \(a^3\) 行,每行若干整数。

第一个数\(g_i\)表示第\(i\)块水晶的好看程度。如果 \(g_i=0\),代表这块水晶会发光。接下来 \(3\sim 6\)个整数,代表与这块水晶有共同面的水晶编号。

输出格式

两个整数,代表水晶立方体在夜晚好看程度的最小值与最大值。

样例

样例输入

2

0 7 2 3

0 8 1 4

4 5 4 1

8 6 3 2

16 3 6 7

32 4 5 8

1 1 8 5

2 2 7 6

样例输出

0 12

数据范围与提示

对于所有数据,\(1<a\le 70, gi<1000000, n\le 8\)。

题解

首先,介绍一下c++ stl里的神物——stringstream

这东西能像cin那样读入,但是是从字符串中读入,所以我们就不用打快读了(虽然慢了一点,但开氧气之后海星)。

头文件<sstream>

大概就是这样读:

for(int i = 1; i <= n; ++i)
{
getline(cin, tmp);
stringstream ss(tmp);
ss >> dep[i];
int aa;
while(ss >> aa)
add_edge(i, aa);
}

题目中的照射不仅只照到了与该水晶相邻的水晶,它把整条射线上的水晶全照到了。

所以我们只能考虑建出这个立方体后重新建图。

我的思路是这样的:

先找到一个度为3的点作为一个角的点,用bfs求出其道个点的最短路。记以该点为原点的第\(i\)个点坐标为\((x_{1, i}, y_{1, i}, z_{1, i})\),最短路为\(dist[0][i]\),显然有\(dist[0][i] = x_{1, i} - 1+ y_{1, i} - 1 + z_{1, i} - 1\)。

我们任选一个平面,要求包含刚才那个点。我们找到在该平面上该点对角线上的点,其实就是随便找一个度为3(在角上)且与原点距离\(2(n-1)\)(在该平面上最远)的点。以该点为原点跑一遍最短路,记\(dist[1][i]\)。

由于我们设计最短路时,可以先走到该点正下方,再往上爬,同样,我们可以设计成先走\(y\),再走\(x\),最后走\(z\)。

我们发现\(dist[0][i] +dist[1][i]=2(n-1)\),我们把它减去,就只剩下\(2z\)了,于是\(z\)就求出来了:

/**
ddn是度数
di是原点
poi记录点的x, y, z
这里的n已经是点的个数了
tn才是边长
由于从1开始,所以有些地方微调了一下
*/
for(di[0] = 1; ddn[di[0]] > 3; ++di[0]);
bfs(0);
for(int i = 1; i <= n; ++i)
{
if(ddn[i] == 3 && dist[0][i] == ((tn-1)<<1))
{
di[1] = i;
break;
}
}
bfs(1);
for(int i = 1; i <= n; ++i)
poi[i].z = (dist[0][i] + dist[1][i] - ((tn-2)<<1)) >> 1;

我们可以用同样的方法把\(x\)解出来,最后的\(y\)只要减一下就可以了。因为我的坐标是从1开始的,所以我对坐标做了一些微调,从0开始就没有这个问题。

由于之前bfs的数据我们还能用,所以我们只需再一遍bfs即可

for(int i = 1; i <= n; ++i)
if(poi[i].z == tn && dist[0][i] == dist[1][i] && ddn[i] == 3)
di[2] = i;
bfs(2);
for(int i = 1; i <= n; ++i)
{
poi[i].x = (dist[0][i] + dist[2][i] - ((tn-1)<<1)) >> 1;
poi[i].y = (dist[0][i] - poi[i].x - poi[i].z) + 1;
poi[i].x++;
poi[i].y++;
mmap[poi[i].x][poi[i].y][poi[i].z] = i;
}

于是我们就建好图了。

后面的大力dfs也没什么好说的。

下面把ac代码贴一下,由于stringstream在没有氧气的情况下极慢,所以必须开氧气。

// luogu-judger-enable-o2
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>//stringstream
#include <queue> using namespace std; const int maxm = 2058000;//这里的最大边数我是把点数加起来乘了6
const int maxn = 75*75*75;
const int inf = 0x3f3f3f3f; int n;//总个数
int tn;//边长 struct Edge
{
int to, nxt;
} e[maxm<<1]; int first[maxn]; int cnt;
inline void add_edge(int f, int t)
{
e[++cnt].nxt = first[f];
first[f] = cnt;
e[cnt].to = t;
} int dirx[] = {1, -1, 0, 0, 0, 0};
int diry[] = {0, 0, 1, -1, 0, 0};
int dirz[] = {0, 0, 0, 0, 1, -1}; int dep[maxn];//"好看程度"
int vis[maxn];
int minn = inf;
int maxx = -inf;
int ll[10];//会发光的水晶的编号
int ddn[maxn];//度数
int zl;//这是个ddn的cnt
int mmap[73][73][73]; struct zb
{
int x, y, z;
} poi[maxn]; #define pan (x > 0 && x <= tn && y > 0 && y <= tn && z > 0 && z <= tn)
#define nxxt x += dirx[i], y += diry[i], z += dirz[i] inline int getans(int i, zb a)//能加多少"好看程度"
{
int ans = 0;
int x = a.x, y = a.y, z = a.z;
for(; pan; nxxt)
if(!vis[mmap[x][y][z]]++)//由于待会儿回溯时要删除,所以懒到家的我就直接用++,--代替记录了
ans += dep[mmap[x][y][z]];
return ans;
} inline void delvis(int i, zb a)//回溯时把dfs前加的vis删除
{
int x = a.x, y = a.y, z = a.z;
for(; pan; nxxt)
vis[mmap[x][y][z]]--;
} inline void dfs(int now, int ans)//大力枚举所有情况
{
if(now > zl)
{
minn = min(minn, ans);
maxx = max(maxx, ans);
return;
}
for(int i = 0; i < 6; ++i)
{
dfs(now+1, ans + getans(i, poi[ll[now]]));
delvis(i, poi[ll[now]]);
}
} int dist[4][maxn];
int di[4];
bool viss[maxn]; inline void bfs(int id)//求最短路
{
memset(viss, 0, sizeof(viss));
queue<int> q;
int from = di[id];
viss[from] = true;
q.push(from);
while(!q.empty())
{
int now = q.front();
q.pop();
for(int i = first[now]; i; i = e[i].nxt)
{
int to = e[i].to;
if(!viss[to])
{
viss[to] = true;
dist[id][to] = dist[id][now] + 1;
q.push(to);
}
}
}
} int main()
{
ios:: sync_with_stdio(false);
cin >> n;
tn = n;
string tmp;
getline(cin, tmp);
n *= n * n;
for(int i = 1; i <= n; ++i)
{
getline(cin, tmp);
stringstream ss(tmp);
ss >> dep[i];
int aa;
if(!dep[i])
{
vis[i] = true;
ll[++zl] = i;
}
while(ss >> aa)
{
add_edge(i, aa);
ddn[i]++;
}
}
for(di[0] = 1; ddn[di[0]] > 3; ++di[0]);
bfs(0);
for(int i = 1; i <= n; ++i)
{
if(ddn[i] == 3 && dist[0][i] == ((tn-1)<<1))
{
di[1] = i;
break;
}
}
bfs(1);
for(int i = 1; i <= n; ++i)//得到z
{
poi[i].z = (dist[0][i] + dist[1][i] - ((tn-2)<<1)) >> 1;
if(poi[i].z == tn && dist[0][i] == dist[1][i] && ddn[i] == 3)
di[2] = i;
}
bfs(2);
for(int i = 1; i <= n; ++i)//得到x, y
{
poi[i].x = (dist[0][i] + dist[2][i] - ((tn-1)<<1)) >> 1;
poi[i].y = (dist[0][i] - poi[i].x - poi[i].z) + 1;
poi[i].x++;
poi[i].y++;
mmap[poi[i].x][poi[i].y][poi[i].z] = i;
}
dfs(1, 0);
cout << minn << ' ' << maxx << endl;
fclose(stdin);
fclose(stdout);
return 0;
}

原题链接

题目描述

金先生有一个女朋友没名字。她勤劳勇敢、智慧善良。金先生很喜欢她。为此,金先生用\(a^3\)块\(1 \times 1 \times 1\)的独特的水晶制作了一个边长为\(a\)的水晶立方体,他要将这个水晶立方体送给他见过最单纯善良的她。

由于水晶立方体太太,不好运送,金先生还是将它拆开来送出。他相信拼好这个水晶立方难不倒聪明的她。

没名字收到了礼物后果然不一会儿就根据说明将水晶立方体拼好了。没名字发现,有 nnn 块水晶在漆黑安静的夜晚会随机以等概率向上下左右前后六个方向的一个发出光。被光照到的水晶显得格外好看。没名字给每一块不会发光的水晶定义了一个好看程度。水晶立方体在夜晚中的好看程度就是每块被光照到的水晶的好看程度之和。没名字想知道,水晶立方体在夜晚中的好看程度的最小值和最大值。

输入格式

第一行是 \(a\),表示水晶立方体的边长。

接下来 \(a^3\)​​ 行,每行若干整数。

第一个数\(g_i\)表示第\(i\)块水晶的好看程度。如果 \(g_i=0\),代表这块水晶会发光。接下来 \(3\sim 6\)个整数,代表与这块水晶有共同面的水晶编号。

输出格式

两个整数,代表水晶立方体在夜晚好看程度的最小值与最大值。

样例

样例输入

2

0 7 2 3

0 8 1 4

4 5 4 1

8 6 3 2

16 3 6 7

32 4 5 8

1 1 8 5

2 2 7 6

样例输出

0 12

数据范围与提示

对于所有数据,\(1<a\le 70, gi<1000000, n\le 8\)。

题解

首先,介绍一下c++ stl里的神物——stringstream

这东西能像cin那样读入,但是是从字符串中读入,所以我们就不用打快读了(虽然慢了一点,但开氧气之后海星)。

头文件<sstream>

大概就是这样读:

for(int i = 1; i <= n; ++i)
{
getline(cin, tmp);
stringstream ss(tmp);
ss >> dep[i];
int aa;
while(ss >> aa)
add_edge(i, aa);
}

题目中的照射不仅只照到了与该水晶相邻的水晶,它把整条射线上的水晶全照到了。

所以我们只能考虑建出这个立方体后重新建图。

我的思路是这样的:

先找到一个度为3的点作为一个角的点,用bfs求出其道个点的最短路。记以该点为原点的第\(i\)个点坐标为\((x_{1, i}, y_{1, i}, z_{1, i})\),最短路为\(dist[0][i]\),显然有\(dist[0][i] = x_{1, i} - 1+ y_{1, i} - 1 + z_{1, i} - 1\)。

我们任选一个平面,要求包含刚才那个点。我们找到在该平面上该点对角线上的点,其实就是随便找一个度为3(在角上)且与原点距离\(2(n-1)\)(在该平面上最远)的点。以该点为原点跑一遍最短路,记\(dist[1][i]\)。

由于我们设计最短路时,可以先走到该点正下方,再往上爬,同样,我们可以设计成先走\(y\),再走\(x\),最后走\(z\)。

我们发现\(dist[0][i] +dist[1][i]=2(n-1)\),我们把它减去,就只剩下\(2z\)了,于是\(z\)就求出来了:

/**
ddn是度数
di是原点
poi记录点的x, y, z
这里的n已经是点的个数了
tn才是边长
由于从1开始,所以有些地方微调了一下
*/
for(di[0] = 1; ddn[di[0]] > 3; ++di[0]);
bfs(0);
for(int i = 1; i <= n; ++i)
{
if(ddn[i] == 3 && dist[0][i] == ((tn-1)<<1))
{
di[1] = i;
break;
}
}
bfs(1);
for(int i = 1; i <= n; ++i)
poi[i].z = (dist[0][i] + dist[1][i] - ((tn-2)<<1)) >> 1;

我们可以用同样的方法把\(x\)解出来,最后的\(y\)只要减一下就可以了。因为我的坐标是从1开始的,所以我对坐标做了一些微调,从0开始就没有这个问题。

由于之前bfs的数据我们还能用,所以我们只需再一遍bfs即可

for(int i = 1; i <= n; ++i)
if(poi[i].z == tn && dist[0][i] == dist[1][i] && ddn[i] == 3)
di[2] = i;
bfs(2);
for(int i = 1; i <= n; ++i)
{
poi[i].x = (dist[0][i] + dist[2][i] - ((tn-1)<<1)) >> 1;
poi[i].y = (dist[0][i] - poi[i].x - poi[i].z) + 1;
poi[i].x++;
poi[i].y++;
mmap[poi[i].x][poi[i].y][poi[i].z] = i;
}

于是我们就建好图了。

后面的大力dfs也没什么好说的。

下面把ac代码贴一下,由于stringstream在没有氧气的情况下极慢,所以必须开氧气。

// luogu-judger-enable-o2
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>//stringstream
#include <queue> using namespace std; const int maxm = 2058000;//这里的最大边数我是把点数加起来乘了6
const int maxn = 75*75*75;
const int inf = 0x3f3f3f3f; int n;//总个数
int tn;//边长 struct Edge
{
int to, nxt;
} e[maxm<<1]; int first[maxn]; int cnt;
inline void add_edge(int f, int t)
{
e[++cnt].nxt = first[f];
first[f] = cnt;
e[cnt].to = t;
} int dirx[] = {1, -1, 0, 0, 0, 0};
int diry[] = {0, 0, 1, -1, 0, 0};
int dirz[] = {0, 0, 0, 0, 1, -1}; int dep[maxn];//"好看程度"
int vis[maxn];
int minn = inf;
int maxx = -inf;
int ll[10];//会发光的水晶的编号
int ddn[maxn];//度数
int zl;//这是个ddn的cnt
int mmap[73][73][73]; struct zb
{
int x, y, z;
} poi[maxn]; #define pan (x > 0 && x <= tn && y > 0 && y <= tn && z > 0 && z <= tn)
#define nxxt x += dirx[i], y += diry[i], z += dirz[i] inline int getans(int i, zb a)//能加多少"好看程度"
{
int ans = 0;
int x = a.x, y = a.y, z = a.z;
for(; pan; nxxt)
if(!vis[mmap[x][y][z]]++)//由于待会儿回溯时要删除,所以懒到家的我就直接用++,--代替记录了
ans += dep[mmap[x][y][z]];
return ans;
} inline void delvis(int i, zb a)//回溯时把dfs前加的vis删除
{
int x = a.x, y = a.y, z = a.z;
for(; pan; nxxt)
vis[mmap[x][y][z]]--;
} inline void dfs(int now, int ans)//大力枚举所有情况
{
if(now > zl)
{
minn = min(minn, ans);
maxx = max(maxx, ans);
return;
}
for(int i = 0; i < 6; ++i)
{
dfs(now+1, ans + getans(i, poi[ll[now]]));
delvis(i, poi[ll[now]]);
}
} int dist[4][maxn];
int di[4];
bool viss[maxn]; inline void bfs(int id)//求最短路
{
memset(viss, 0, sizeof(viss));
queue<int> q;
int from = di[id];
viss[from] = true;
q.push(from);
while(!q.empty())
{
int now = q.front();
q.pop();
for(int i = first[now]; i; i = e[i].nxt)
{
int to = e[i].to;
if(!viss[to])
{
viss[to] = true;
dist[id][to] = dist[id][now] + 1;
q.push(to);
}
}
}
} int main()
{
ios:: sync_with_stdio(false);
cin >> n;
tn = n;
string tmp;
getline(cin, tmp);
n *= n * n;
for(int i = 1; i <= n; ++i)
{
getline(cin, tmp);
stringstream ss(tmp);
ss >> dep[i];
int aa;
if(!dep[i])
{
vis[i] = true;
ll[++zl] = i;
}
while(ss >> aa)
{
add_edge(i, aa);
ddn[i]++;
}
}
for(di[0] = 1; ddn[di[0]] > 3; ++di[0]);
bfs(0);
for(int i = 1; i <= n; ++i)
{
if(ddn[i] == 3 && dist[0][i] == ((tn-1)<<1))
{
di[1] = i;
break;
}
}
bfs(1);
for(int i = 1; i <= n; ++i)//得到z
{
poi[i].z = (dist[0][i] + dist[1][i] - ((tn-2)<<1)) >> 1;
if(poi[i].z == tn && dist[0][i] == dist[1][i] && ddn[i] == 3)
di[2] = i;
}
bfs(2);
for(int i = 1; i <= n; ++i)//得到x, y
{
poi[i].x = (dist[0][i] + dist[2][i] - ((tn-1)<<1)) >> 1;
poi[i].y = (dist[0][i] - poi[i].x - poi[i].z) + 1;
poi[i].x++;
poi[i].y++;
mmap[poi[i].x][poi[i].y][poi[i].z] = i;
}
dfs(1, 0);
cout << minn << ' ' << maxx << endl;
fclose(stdin);
fclose(stdout);
return 0;
}

题解:[ZJOI2014]璀灿光华的更多相关文章

  1. BZOJ3619 : [Zjoi2014]璀灿光华

    终于把省选时的遗憾补上了… 对于构造立方体: 首先BFS构出底层,然后再逐层构造立方体 对于计算: $O(n^6)$爆搜即可. #include<cstdio> #include<c ...

  2. BZOJ3619 [Zjoi2014]璀灿光华 构造+dfs

    题意:有一个\(a^3\)个小正方体组成的大正方体,其中有n个正方体会向上下左右前后六个方向中的一个发出光,正方体是透光的,被照亮的正方体有个美丽值\(g_{i}\),给出正方体的相邻关系,问美丽值之 ...

  3. 「ZJOI2014」璀灿光华

    「ZJOI2014」璀灿光华 实际上,可以不用建水晶立方体... 因为,发光水晶的方向都要枚举一遍. 只需知道发光水晶每个方向有哪些水晶就可以了. 对于一个发光水晶,将它连接的水晶标号. 从该水晶bf ...

  4. [题解] [ZJOI2014] 力

    题面 题解 恩, 我们首先有这两个关系 \[ \displaystyle\begin{aligned} F_j &= \sum_{i < j}\frac{q_iq_j}{(i - j)^ ...

  5. ZJOI2017 Day1

    私のZJOI Day1 2017-3-21 07:52:53 有人在暴力膜 苟-- 富贵 无相忘 ZJOI2017交流群 133135071 如果你足够厉害 如果你足够厉害 如果你足够厉害 其实完全可 ...

  6. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  7. #知识#室内设计原理ing

    室内设计原理 第一章 室内设计的含义和基本观点 人的一生,绝大部分时间是在室内度过的,因此,人们设计创造的室内环境,必然会直接关系到室内生活.生产活动的质量,关系到人们的安全.健康.效率.舒适等等.室 ...

  8. 逐浪web无障碍与国际化以及全民族语言支持白皮书

    北京时间2019年5月10日,领先的门户网站与WEB内核服务厂商--上海Zoomla!逐浪CMS团队发布其年度重榜产品:逐浪CMS全民族语言与国际版,体验站点:http://demo2.z01.com ...

  9. bzoj 3528 [ZJOI2014] 星系调查 题解

    [原题] 星系调查 [问题描写叙述] 银河历59451年.在银河系有许很多多已被人类殖民的星系.如果想要在行 星系间往来,大家一般使用连接两个行星系的跳跃星门.  一个跳跃星门能够把 物质在它所连接的 ...

随机推荐

  1. ST表基础模板

    ST表是用来求RMQ问题(求区间最大或最小值问题)的实用数据结构,支持\(O(nlog_n)\)建立,\(O(1)\)查询,是比较高效的结构 其原理实质上是DP(我最讨厌的东西) 题面:屠龙宝刀... ...

  2. java8 LinkedHashMap 原理

    LinkedHashMap 原理 基于jdk1.8 HashMap原理:http://www.cnblogs.com/zhaojj/p/7805376.html LinkedHashMap 继承Has ...

  3. docker Dockerfile实战

    目录 Dockerfile实战 基础pm2 Dockerfile keymetrics/pm2:8-alpine keymetrics/pm2:12-alpine pm2 node Dockerfil ...

  4. 记录战斗记录你,详解妖尾战斗录像系统[Unity]

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  5. UVA 291 The House Of Santa Claus DFS

    题目: In your childhood you most likely had to solve the riddle of the house of Santa Claus. Do you re ...

  6. 【题解】Informacije [COCI2012]

    [题解]Informacije [COCI2012] 传送门:官方题面 [题目描述] 有一个长度为 \(n\) 的 序列 \(a\)(由 \([1,n]\) 中的数组成,且每个数只会出现一次),现给出 ...

  7. IIS Express 启用目录浏览 方法

    标签: iis / visual studio / C# / ASP.NET / .NET 522 今天刚刚使用visual studio 2013创建第一个hello world,结果就发现提示错误 ...

  8. layui + mvc + ajax 导出Excel功能

    为了更方便,没基础的伙伴更容易理解,我尽量详细简便 省了很多代码,一步一步的试 自己引入文件 1. html 前端视图代码 Layui的数据绑定 全部代码 @{ Layout = null; } &l ...

  9. python算法题 python123网站单元四题目

    目录 一:二分法求平方根 二:Collatz猜想 三:算24(只考虑满足,不考虑把所有情况找出来)   下面向大家介绍几个python算法题. 一:二分法求平方根 1.题目要求为 2.输入输出格式为 ...

  10. Flask--闪现、中间件、多app应用

    目录 闪现 源码 案例 中间件 自定义局部中间件 自定义全局装饰器 多app应用 闪现 flask提供了一个非常有用的flash()函数,它可以用来"闪现"需要提示给用户的消息,比 ...