洛谷P7528 [USACO21OPEN] Portals G
P7528 [USACO21OPEN] Portals G
luogu题目传送门
题目描述
Bessie 位于一个由 N N N 个编号为 1 … N 1\dots N 1…N 的结点以及 2 N 2N 2N 个编号为 1 ⋯ 2 N 1\cdots 2N 1⋯2N 的传送门所组成的网络中。每个传送门连接两个不同的结点 u u u 和 v v v( u ≠ v u≠v u=v)。可能有多个传送门连接同一对结点。
每个结点 v v v 与四个不同的传送门相连。与 v v v 相连的传送门列表由 p v = [ p v , 1 , p v , 2 , p v , 3 , p v , 4 ] p_v=[p_{v,1},p_{v,2},p_{v,3},p_{v,4}] pv=[pv,1,pv,2,pv,3,pv,4] 给出。
你的当前位置可以用有序对(当前结点,当前传送门)表示;即一个有序对 ( v , p v , i ) (v,p_{v,i}) (v,pv,i)
,其中 1 ≤ v ≤ N 1\le v\le N 1≤v≤N 以及 1 ≤ i ≤ 4 1\le i\le 4 1≤i≤4。你可以使用以下任一操作来改变你的当前位置:
-
- 由穿过当前传送门来改变当前结点。
-
- 改变当前传送门。在每一个结点上,列表的前两个传送门是配对的,后两个传送门也是配对的。也就是说,如果你的当前位置是 ( v , p v , 2 ) (v,p_{v,2}) (v,pv,2),你可以转而使用传送门 ( v , p v , 1 ) (v,p_{v,1}) (v,pv,1),反之亦然。类似地,如果你的当前位置是 ( v , p v , 3 ) (v,p_{v,3}) (v,pv,3),你可以转而使用传送门 ( v , p v , 4 ) (v,p_{v,4}) (v,pv,4),反之亦然。没有其他改变传送门的方式(例如,你不能从传送门 p v , 2 p_{v,2} pv,2 转去传送门 p v , 4 p_{v,4} pv,4 )。
总共有 4 N 4N 4N 个不同的位置。不幸的是,并不一定每一个位置都可以从另外的每一个位置经过一系列操作而到达。所以,以 c v c_v cv 哞尼的代价,你可以以任意顺序重新排列与 v v v 相邻的传送门列表。在此之后,列表中的前两个传送门互相配对,同时后两个传送门也互相配对。
例如,如果你将与 v v v 相邻的传送门以 [ p v , 3 , p v , 1 , p v , 2 , p v , 4 ] [p_{v,3},p_{v,1},p_{v,2},p_{v,4}] [pv,3,pv,1,pv,2,pv,4] 的顺序重新排列,这意味着如果你位于结点 v v v ,
- 如果你当前位于传送门 p v , 1 p_{v,1} pv,1 ,你可以转而使用传送门 p v , 3 p_{v,3} pv,3,反之亦然。
- 如果你当前位于传送门 p v , 2 p_{v,2} pv,2 ,你可以转而使用传送门 p v , 4 p_{v,4} pv,4,反之亦然。
你不再能够从传送门 p v , 1 p_{v,1} pv,1
转至传送门 p v , 2 p_{v,2} pv,2,或从传送门 p v , 3 p_{v,3} pv,3 转至 p v , 4 p_{v,4} pv,4 ,反之亦然。
计算修改这一网络使得每一个位置都可以从另外的每一个位置到达所需要花费的哞尼的最小数量。输入保证存在至少一种修改网络的合法方式。
输入格式
输入的第一行包含 N N N。
以下 N N N 行每行描述一个结点。第 v + 1 v+1 v+1 行包含五个空格分隔的整数 c v , p v , 1 , p v , 2 , p v , 3 , p v , 4 c_v,p_{v,1},p_{v,2},p_{v,3},p_{v,4} cv,pv,1,pv,2,pv,3,pv,4。
输入保证对于每一个 v v v , p v , 1 , p v , 2 , p v , 3 , p v , 4 p_{v,1},p_{v,2},p_{v,3},p_{v,4} pv,1,pv,2,pv,3,pv,4 各不相同,且每个传送门出现在恰好两个结点的邻接表中。
输出格式
输出一行,包含修改这一网络使得每一个位置都可以从另外的每一个位置到达所需要花费的哞尼的最小数量。
输入输出样例 #1
输入 #1
5
10 1 4 8 9
11 1 2 5 6
12 9 10 2 3
3 4 3 6 7
15 10 8 7 5
输出 #1
13
说明/提示
样例解释
重新排列结点 1 1 1 和 4 4 4 的邻接表就已足够。这需要总计 c 1 + c 4 = 13 c_1+c_4=13 c1+c4=13 哞尼。我们可以使 p 1 = [ 1 , 9 , 4 , 8 ] p_1=[1,9,4,8] p1=[1,9,4,8] 以及 p 4 = [ 7 , 4 , 6 , 3 ] p_4=[7,4,6,3] p4=[7,4,6,3]。
数据范围与约定
2 ≤ N ≤ 1 0 5 2\le N\le 10^5 2≤N≤105, 1 ≤ c v ≤ 1 0 3 1\le c_v\le 10^3 1≤cv≤103。
思路
首先先翻译一下这冗长的题目:
给定N个节点,对于每个节点u,u与4个传送门相连,你可以从一个节点通过传送门到达其他节点,且初始1,2号、3,4号传送门是相连的。你可以花费 c v c_{v} cv元改变连通顺序,但原来的连通会被废除
那么想要到达每一个节点吗,我们只需要到达每一个传送门即可,那样例的图可化为:
这时我们会发现,每一个连通块恰好为一个环,那这有什么用呢?
由于我们需要将每个连通块合并,但我们担心的是如果我们调换传送门的顺序,我们会不会把当前的连通块打碎?
由于每个连通块恰好为一个环,我们改变顺序后,肯定会打破两条边,而且这两条边一定不在一个环上,由此打破两条边后,会得到两条链,将链连接起来后,又是一条环,这样就可以一直合并。
不过我们还需要证明一下每一个连通块必定是一个环
因为每个传送门与两个节点相连,所以他的度数为2(与其他传送门相连的度数),所以连通块必定是一个环
那这样就很好做了,我们一开始先将所有的连通块处理出来,由于要连通,我们很容易就想到了最小生成树,由此用kruskal求解即可
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int fa[N],n;
struct lit{int x,y,z;friend bool operator<(lit t1,lit t2){return t1.z<t2.z;}
}b[N];
int o=0;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void merge(int x,int y){//合并int f1=find(x),f2=find(y);if(f1!=f2)fa[f1]=f2;
}
int main(){cin>>n;for(int i=1;i<=n*2;i++)fa[i]=i;//记得要初始化,而且是2*N个传送门初始化for(int i=1;i<=n;i++){int c,x,y,z,w;cin>>c>>x>>y>>z>>w;merge(x,y);merge(z,w);//不需要花钱,直接合并b[++o]={x,z,c};//改变顺序需要花费c元,由于z,w连通,改到x,z与x,w一致}sort(b+1,b+1+o);int ans=0;for(int i=1;i<=o;i++){int f1=find(b[i].x),f2=find(b[i].y);if(f1!=f2){fa[f1]=f2;ans+=b[i].z;}}//最小生成树cout<<ans<<'\n';return 0;
}
总结
对于这种题目描述冗长的题目,一定要先简化题目再做题,不要向我·一样被题目所迷惑