E - The Cake Is a Lie
题意:
输入一个n,给出n-2个三角形。然后把他们拼成一个多边形,多边形的序号和三角形的序号对应,可以是乱序。输出两个东西,一个是三角形的序号,可以随便以哪个序号开头都可以,第二个东西就是我们按照那种顺序拿。
题解:
我们知道每个这个多边形分成n-2个三角形的过程中,每个边最多使用两次,使用一次的边一定是凸包上的边。所以我们这里想到了异或,让和这个顶点相连接的每个顶点都和他异或一下,为什么呢?我们自己考虑,一个顶点如果是在使用两条边上面,那么和它相连接的定点一定有一个顶点和他异或了两次(所以低抵消了)所以三个顶点(不包括自己)只剩下了两个,最后我们拿出只是用一次的边的两个顶点,再和它异或的值异或一下,一定可以抵消只剩下一个顶点,所以我们序号的顺序可以这样处理出来。然后我们怎么输出我们拿三角形的顺序,我们可以通过在三角形之间加连边,使用两次的三角形我们建立一个无向边就可以了。然后按照叶子节点输出。
至于为什么一定要保证a,b,c有序,是因为保证边的唯一性,比如第一次有1,3,第二次是3,1那么就成两条边了,其实是一条。
#include<bits/stdc++.h>
using namespace std;
map<pair<int,int> , vector<int> > m;
const int N=1e5+7;
vector<int> p[N];
int n,e[N];
void init()
{
for(int i=0;i<=n+1;i++) p[i].clear(),e[i]=0;
m.clear();
}
void dfs(int u,int f){
// cout<<"---"<<u<<endl;
// cout<<u<<' ';
for(int i=0;i<p[u].size();i++){
if(p[u][i]==f) continue;
dfs(p[u][i],u);
}
printf("%d ",u);
}
int main()
{
int t ; cin>>t;
while(t--){
scanf("%d",&n);
init();
for(int i=1;i<=n-2;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a>b) swap(a,b);
if(b>c) swap(b,c);
if(a>b) swap(a,b);
e[a]^=b,e[a]^=c;
e[b]^=a,e[b]^=c;
e[c]^=b,e[c]^=a;
m[{a,b}].push_back(i);
m[{b,c}].push_back(i);
m[{a,c}].push_back(i);
}
int x,y;
for(auto u:m){
if(u.second.size()==1){
x=u.first.first;
y=u.first.second;
break;
}
}
printf("%d %d ",x,y);
for(int i=1 ;i<=n-2;i++,swap(x,y)) printf("%d ",(x^=e[y]));
for(auto u:m){
if(u.second.size()==2){
p[u.second[0]].push_back(u.second[1]);
p[u.second[1]].push_back(u.second[0]);
}
}
puts("");
// cout<<"----"<<endl;
dfs(1,0);
printf("\n");
}
}
来源:CSDN
作者:行走天涯的豆沙包
链接:https://blog.csdn.net/weixin_42979819/article/details/103757122