Gym 102411 C 十字绣

https://codeforces.com/gym/102411

题意:在w*h(1<=w,h<=100)的布上绣十字绣,要求在给定的方格上连石子,图案正面每段只能走一次。需要在用一根线绣完整幅图,而且使用线的长度最短。在背面可以往相邻8个方向走,而且可以重复。输出一种方案。

观察样例,我们可以大胆猜想背面只需要走横线或竖线,而且每个格子配两条横线或竖线,即最少需要走4*a-1段路径。我们应该可以通过类似奇偶性的方法证明最优方案长度不小于这样4*a-1段。下一步需要构造出这样的方案。

我们需要在横线和斜线上交替走,而且每条边恰好经过一次,可以发现与欧拉路径有关。由于难以处理无向图欧拉回路度数的奇偶性,所以我们尝试对每条边定向,建立有向图的欧拉回路。参照原来有向图有欧拉回路每个点入度与出度相等的条件,这里要求正面入度=反面出度,反面入度=正面出度。一个简单的图块就可以满足这个条件:

竖线是背面的边

然而这样直接拼接起来跑欧拉路径出来并不是完整的图。。。观察一下,会发现这样建出来的图裂开了。。。虽然度数满足要求了,但是要使路径满足第一个条件,图会裂成几个连通块。

我们想办法使构造出来的图连通。最简单的方式,只要把上面的building blocks转转就行了。构造方法就是2*2的块每块的箭头分别指向不同的方向。容易看出这样的图一定是连通的。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<queue>
  6. #include<map>
  7. #include<stack>
  8. #include<cmath>
  9. #include<set>
  10. #include<bitset>
  11. #include<complex>
  12. #include<cstdlib>
  13. #include<assert.h>
  14. #define inc(i,l,r) for(int i=l;i<=r;i++)
  15. #define dec(i,l,r) for(int i=l;i>=r;i--)
  16. #define link(x) for(edge *j=h[x];j;j=j->next)
  17. #define mem(a) memset(a,0,sizeof(a))
  18. #define ll long long
  19. #define mid (x+y>>1)
  20. #define eps 1e-8
  21. #define succ(x) (1<<(x))
  22. #define lowbit(x) (x&(-x))
  23. #define sqr(x) ((x)*(x))
  24. #define MAXN 200005
  25. #define nm 20000005
  26. using namespace std;
  27. const double pi=acos(-1);
  28. const ll inf=1e9+7;
  29. ll read(){
  30.     ll x=0,f=1;char ch=getchar();
  31.     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  32.     while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
  33.     return f*x;
  34. }
  35. struct edge{int t;bool st,vis; edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
  36. void add(int x,int y, bool st){
  37.     //cout<<x<<" to "<<y<<'\n';
  38.     o->t=y; o->st=st; o->vis=0; o->next=h[x];h[x]=o++;}
  39.  
  40. char a[110][110];
  41. int ansp[MAXN], al;
  42.  
  43. void euler(int u, int st){
  44.     link(u) if (!j->vis && j->st==st){
  45. 	j->vis=1;
  46. 	euler(j->t,st^1);
  47.     }
  48.     ansp[al++]=u;
  49. }
  50.  
  51.  
  52. int main(){    
  53.     int w,h;
  54.     w=read(),h=read();
  55.     inc(i,1,h) scanf("%s",a[i]+1);
  56.     int sp=-1;
  57.     inc(i,1,h) inc(j,1,w){
  58. 	if (a[i][j]=='X'){
  59. 	    if ((i&1) && (j&1)){
  60. 		add((i-1)*(w+1)+j-1,i*(w+1)+j,0);
  61. 		add((i-1)*(w+1)+j,  i*(w+1)+j-1,0);
  62. 		add(i*(w+1)+j-1,(i-1)*(w+1)+j-1,1);
  63. 		add(i*(w+1)+j,(i-1)*(w+1)+j,1);
  64. 		sp=(i-1)*(w+1)+j-1;
  65. 	    }
  66. 	    else if (!(i&1) && !(j&1)){
  67. 		add(i*(w+1)+j,(i-1)*(w+1)+j-1,0);
  68. 		add( i*(w+1)+j-1,(i-1)*(w+1)+j, 0);
  69. 		add((i-1)*(w+1)+j-1,i*(w+1)+j-1,1);
  70. 		add((i-1)*(w+1)+j,i*(w+1)+j, 1);
  71. 		sp=(i)*(w+1)+j;
  72. 		}
  73. 	    else if (!(i&1) && (j&1)){
  74. 		add((i)*(w+1)+j-1,(i-1)*(w+1)+j,0);
  75. 		add((i-1)*(w+1)+j-1,(i)*(w+1)+j,0);
  76. 		add((i-1)*(w+1)+j,(i-1)*(w+1)+j-1,1);
  77. 		add((i)*(w+1)+j,(i)*(w+1)+j-1, 1);
  78. 		sp=(i-1)*(w+1)+j-1;
  79. 	    }
  80. 	    else{
  81. 		add((i-1)*(w+1)+j,(i)*(w+1)+j-1,0);
  82. 		add((i)*(w+1)+j,(i-1)*(w+1)+j-1,0);
  83. 		add((i-1)*(w+1)+j-1,(i-1)*(w+1)+j,1);
  84. 		add((i)*(w+1)+j-1, (i)*(w+1)+j,1);
  85. 		sp=(i)*(w+1)+j;
  86. 		}
  87. 	}
  88.     }
  89.     euler(sp,0);
  90.     printf("%d\n",al-2);
  91.     dec(i,al-1,1){
  92. 	printf("%d %d\n",ansp[i]%(w+1),ansp[i]/(w+1));
  93.     }
  94.     return 0;
  95. }

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注