hdu5302 构造
题意:
一个无向图,每条边要么是白色要么是黑色
每个点最多与2条白边相连,每个点最多与两条黑边相连
现在告诉你w0, w1, w2和b0, b1, b2
表示有wi个点周围有i条白边, 有bi个点周围有i条黑边
现在要求构造这个图,没有自环重边,且满足wi, bi的要求,输出每条边以及颜色
思路:
n<=4可以手动构造
对于n>4, 我们首先可以在n个点上构造一个白环,一个黑环,每个环都包括所有点,并且没有重边
对于奇数n:
白环 1 2 3 ... n
黑环 1 3 5 ... n 2 4 6 ... n-1
对于偶数n:
白环 1 2 3 ... n
黑环 1 3 5 ... n-1 2 n n-2 n-4 ... 4
最后的答案肯定是这个双环的子图
白色和黑色是独立的,可以分开考虑
例如白边,把所有2°点排成一排,在两端各放一个1°点,剩下来的1°点两两配对,0°点不考虑
只要1°点是偶数就有解
#include <cstdio> #include <vector> using namespace std; const int N = 6000; int n, total; int w[3], b[3]; int L[N+5], R[N+5]; vector<int> f[N+5], g[N+5]; inline void con(vector<int> ch[], int a, int b){ ++total; if (a<b) ch[a].push_back(b); else ch[b].push_back(a); } inline void go(int c[], vector<int> ch[]){ int st = 1, ed; for (int i=1, u=1; i<=c[2]; i++, u=R[u]){ if (i == c[2]){ ed = u; } else{ con(ch, u, R[u]); } } con(ch, L[st], st); con(ch, ed, R[ed]); for (int i=1, u=R[R[ed]]; i<=c[1]-2; i+=2, u=R[R[u]]){ con(ch, u, R[u]); } } void output(){ printf("%d\n", total); for (int i=1; i<=n; i++){ for (int j=0; j<f[i].size(); j++){ printf("%d %d 0\n", i, f[i][j]); } for (int j=0; j<g[i].size(); j++){ printf("%d %d 1\n", i, g[i][j]); } } } int main(){ //freopen("1003.in", "r", stdin); //freopen("1003.txt", "w", stdout); int test; scanf("%d", &test); for (int T=1; T<=test; T++){ n = total = 0; for (int i=0; i<3; i++) scanf("%d", &w[i]); for (int i=0; i<3; i++) scanf("%d", &b[i]); for (int i=0; i<3; i++) n += w[i]; for (int i=1; i<=n; i++){ f[i].clear(); g[i].clear(); } if ((w[1]&1) || (b[1]&1)){ puts("-1"); continue; } if (n==4){ con(f, 1, 2); con(f, 1, 3); con(g, 4, 2); con(g, 4, 3); output(); continue; } for (int i=1; i<=n; i++){ L[i] = i-1; R[i] = i+1; } L[1] = n; R[n] = 1; go(w, f); if (n&1){ for (int i=1; i<=n; i++){ L[i] = i-2; R[i] = i+2; } L[1] = n-1; R[n-1] = 1; L[2] = n; R[n] = 2; } else{ for (int i=1; i<=n; i+=2){ L[i] = i-2; R[i] = i+2; } for (int i=2; i<=n; i+=2){ L[i] = i+2; R[i] = i-2; } L[1] = 4; R[4] = 1; L[2] = n-1; R[2] = n; L[n] = 2; R[n-1] = 2; } go(b, g); output(); } return 0; }