链接:https://codeforces.com/contest/1282/problem/E
题意:给的是一张平面图,是一个n边形,每次可以切一刀,切出一个三角形,最终切成n-2个三角形。题目给出所切三角形的三个顶点的编号,以及三角形的编号。问你切出的三角形顺序,以及按顺序输出原始n边形顶点的所有编号,可以逆序输出也顺序输出。
题解:有点类似拓扑排序。首先输入三角形三个点,a,b,c,统计出V[a] Xor b Xor c,同理统计V[b],V[c],这样可以保证V[i]的值只能是0 Xor 与i相连的两个点,即使三角形有共用边,多次Xor会消除公用边相连的点。根据这个性质,可以顺序输出所有点的编号。
那么三角形顺序怎么输出呢?首先发现如果一条边是被两个三角形公用的,那么可以依据这条边把两个三角形相连,这样把三角形作为一个节点从而形成了一个图,这个图结构是一颗树,我们就随便找一个叶子节点,从叶子节点开始dfs遍历一遍,输出三角形编号即可。
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<map> 5 #include<algorithm> 6 using namespace std; 7 const int maxn = 1e+5; 8 int v[maxn]; 9 vector<int> g[maxn]; 10 int visit[maxn]; 11 void dfs(int x){ //从叶子节点开始搜索,因为叶子节点必定代表着最靠外的三角形,它的度是1 12 visit[x] = 1; 13 for(int i = 0;i<g[x].size() ;i++){ 14 int cur = g[x][i]; 15 if(visit[cur] ==0) dfs(g[x][i]); 16 // dfs(g[x][i]); 17 } 18 cout<<x<<" "; 19 } 20 int main(){ 21 int t;cin>>t; 22 while(t--){ 23 int n; 24 cin>>n; 25 for(int i = 0;i<=maxn;i++){ 26 v[i] = 0;//初始化V数组 27 visit[i] = 0;//初始化访问数组 28 g[i].clear() ; 29 } 30 map<pair<int,int>,vector<int> > mp; 31 for(int i = 0;i<n-2;i++){ 32 int a,b,c; 33 cin>>a>>b>>c; 34 if(a>b) swap(a,b); 35 if(b>c) swap(b,c); 36 if(a>b) swap(a,b); 37 v[a]^=b,v[a]^=c;//Xor操作 38 v[b]^=a,v[b]^=c; 39 v[c]^=a,v[c]^=b; 40 mp[{a,b}].push_back(i+1);//添加一条边a,b,以及所共用的三角形i+1 41 mp[{a,c}].push_back(i+1); 42 mp[{b,c}].push_back(i+1); 43 } 44 int a,b; 45 for(auto h:mp){ 46 if(h.second.size()==1){ //随便找一条边,只共用一个三角形 47 a = h.first.first; 48 b = h.first.second; 49 // break; 50 } 51 } 52 cout<<a<<" "<<b;//输出这条边 53 for(int i = 0;i<n-2;i++){ 54 int t = a^v[b];//开始做Xor操作。具体可以用笔模拟一下这个过程,理解更清楚 55 cout<<" "<<t; 56 a = b,b = t; 57 } 58 cout<<endl; 59 for(auto h:mp){ 60 if(h.second.size() == 2){ 61 int u = h.second[0],v = h.second[1]; 62 g[u].push_back(v),g[v].push_back(u);//根据共用边以三角形为一个点建图 63 } 64 } 65 dfs(1); 66 cout<<endl; 67 } 68 return 0; 69 }