Codeforces Round #610 (Div. 2) E

E - The Cake Is a Lie

题意:

输入一个n,给出n-2个三角形。然后把他们拼成一个多边形,多边形的序号和三角形的序号对应,可以是乱序。输出两个东西,一个是三角形的序号,可以随便以哪个序号开头都可以,第二个东西就是我们按照那种顺序拿。

题解:

我们知道每个这个多边形分成n-2个三角形的过程中,每个边最多使用两次,使用一次的边一定是凸包上的边。所以我们这里想到了异或,让和这个顶点相连接的每个顶点都和他异或一下,为什么呢?我们自己考虑,一个顶点如果是在使用两条边上面,那么和它相连接的定点一定有一个顶点和他异或了两次(所以低抵消了)所以三个顶点(不包括自己)只剩下了两个,最后我们拿出只是用一次的边的两个顶点,再和它异或的值异或一下,一定可以抵消只剩下一个顶点,所以我们序号的顺序可以这样处理出来。然后我们怎么输出我们拿三角形的顺序,我们可以通过在三角形之间加连边,使用两次的三角形我们建立一个无向边就可以了。然后按照叶子节点输出。
至于为什么一定要保证a,b,c有序,是因为保证边的唯一性,比如第一次有1,3,第二次是3,1那么就成两条边了,其实是一条。

#include
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<<"---"<
//	cout<
	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<<"----"<
		dfs(1,0);
		printf("\n");
	}
}

你可能感兴趣的:(dfs,思维)