标签:
题意:给你一个无向图,它的边要么是黑色要么是白色,且图上的每个点最多与两个黑边两个白边相连。现在,Demon将图分成两部分,一部分包含所有的黑边,另一部分包括所有的白边,给你白边图中度为0的点的数量w0,度为1的点数w1,度为2的点数w2,与黑边图中度为0的点数b1,度为1的点数b1,度为2的点数b2,要你输出任意一个符合条件的原图,如果不能,输出-1
无论是黑边图,还是白边图,给出的度为0、1、2三种点的数量均>=1 w0+w1+w2==b0+b1+b2,输出图的点数最多为w0+w1+w2个;图中无重边,无自环;
因为 只要白边或者 黑边 度数为1的点 为奇数个 就一定是无解的,因为每个点的白度数和黑度数至多为2,
那么最小是3个点 无解 4点的话 只剩 1 2 1 1 2 1 特判
接下来的 就构造
处理白色的时候 1 2 3 4 5..n 前w2 个分别连接,然后 接下来 从(w2,w2+1)(w2+2,w2+3)...(w2+w1-2,w2+w1-1) 然后再让最大的那个奇数和1相连,为何等等解释
处理黑色的时候1 3 5...2 4 6.... 依照上面的方法连接, 但是最后一条 就是选择 最后一个数和1相连,这样一定是一组解,因为我们排完相邻的不会有在之前相交(n>=5) 那么最大的偶数也不会和1相交,于是就得到解了
解释上面为何使用最大的奇数,就是为了让2和最大的奇数他们放在中间,尽量早的使用,在处理黑色的时候就不会产生无解了,因为最少有一个是没有黑色边度数的,最后一个和1连的 取最后一个便是,因为n>=5最后一个一定是大偶数也不会是2 那么就一定存在一组解
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; const int maxn=2000*3; int a[maxn]; int main() { int w0,w1,w2,b1,b0,b2; int cas; scanf("%d",&cas); for(int cc=1; cc<=cas; cc++) { scanf("%d%d%d%d%d%d",&w0,&w1,&w2,&b0,&b1,&b2); if(w0==0||w1==0||w2==0||b0==0||b1==0||b2==0)while(true); if(w1&1||b1&1){ puts("-1");continue; } int n=w0+w1+w2; if(n==4){ puts("4"); puts("1 2 0"); puts("1 3 0"); puts("4 2 1"); puts("4 3 1"); continue; } printf("%d\n",(w1+w2*2+b1+b2*2)/2 ); for(int i=1;i<w2; i++) printf("%d %d 0\n",i,i+1); for(int i=0;i<w1-1;i+=2){ printf("%d %d 0\n",w2+i,w2+i+1); } int id=(n-1)/2*2+1; printf("%d %d 0\n",1,id); int cnt=0; for(int i=1;i<=n; i+=2){ a[cnt++]=i; } for(int i=2;i<=n; i+=2){ a[cnt++]=i; } for(int i=0;i<b2-1; i++) printf("%d %d 1\n",a[i],a[i+1]); int d=0; for(int i=0; i<b1-1; i+=2){ printf("%d %d 1\n",a[b2-1+i],a[b2+i]); d=max(d,b2+i); } for(int i=d+1; ; i++) if(a[i]!=id&&a[i]!=2){ printf("%d %d 1\n",1,a[i]);break; } } return 0; }
标签:
原文地址:http://www.cnblogs.com/Opaser/p/4852467.html