[构造] ICPC 2016 Hong Kong I. Special Tour

有一个 nm 的网格图,构造一条哈密尔顿回路使得相邻的两个点的距离为 2 或者3,如果无解输出无解。
n,m200

我是dls的脑残粉
这里写图片描述
这里写图片描述

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;

int n,m;
int flag;
inline void print(int x,int y){
  if (flag) swap(x,y); printf("%d %d\n",x,y);
}

const int N=205;

struct edge{
  int u,v,next;
}G[N*N*2];
int head[N*N],inum;
inline void add(int u,int v,int p){
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int vst[N*N];
#define V G[p].v
inline void dfs(int u){
  vst[u]=1; print((u-1)/m+1,(u-1)%m+1);
  for (int p=head[u];p;p=G[p].next)
    if (!vst[V])
      dfs(V);
}
#define DONE (dfs(1),exit(0))

#define P(x,y) (((x)-1)*m+(y))
inline void add(int x1,int y1,int x2,int y2){
  add(P(x1,y1),P(x2,y2),++inum),add(P(x2,y2),P(x1,y1),++inum);
}

inline void Table();

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf("%d%d",&n,&m);
  if ((n==3&&m==3)||(n==5&&m==5)||(n==3&&m==5)||(n==5&&m==3)) Table();
  if (n>m) swap(n,m),flag^=1;
  if (n==1){
    if (m<10 && m!=5) return printf("-1\n"),0;
    add(1,1,1,3),add(1,1,1,4),add(1,2,1,4),add(1,2,1,5);
    if (m==5) add(1,3,1,5),DONE;
    add(1,3,1,6);
    for (int i=7;i<=m-4;i++) add(1,i,1,i-2);
    add(1,m,1,m-2),add(1,m,1,m-3),add(1,m-1,1,m-3),add(1,m-1,1,m-4);
    add(1,m-2,1,m-5);
    DONE;
  }else if (n==2){
    if (m==2) return printf("-1\n"),0;
    add(1,1,2,2),add(1,1,2,3),add(2,1,1,2),add(2,1,1,3);
    for (int i=4;i<=m;i++) add(1,i,1,i-2),add(2,i,2,i-2);
    add(1,m,2,m-1),add(2,m,1,m-1);
    DONE;
  }else if (n==4 || m==4){
    if (n!=4) swap(n,m),flag^=1;
    add(1,1,2,2),add(1,1,2,3),add(2,1,1,2),add(2,1,1,3);
    for (int i=4;i<=m;i++) add(1,i,1,i-2),add(2,i,2,i-2);
    add(3,1,4,2),add(3,1,4,3),add(4,1,3,2),add(4,1,3,3);
    for (int i=4;i<=m;i++) add(3,i,3,i-2),add(4,i,4,i-2);
    add(1,m-1,3,m),add(2,m,4,m-1),add(1,m,2,m-1),add(3,m-1,4,m);
    DONE;
  }else{
    for (int k=1;k<=n;k++){
      add(k,1,k,3),add(k,1,k,4),add(k,2,k,4),add(k,2,k,5);
      add(k,3,k,6);
      for (int i=7;i<=m;i++) add(k,i,k,i-2);
    }
    for (int i=1;i+2<=n;i+=2) add(i,m-1,i+2,m);
    for (int i=2;i+2<=n;i+=2) add(i,m,i+2,m-1);
    if (n&1)
      add(1,m,2,m-1),add(n-1,m,n,m-1);
    else
      add(1,m,2,m-1),add(n-1,m-1,n,m);
    DONE;
  }
  return 0;
}


inline void Table(){
  if (n==3 && m==3) printf("1 1\n2 2\n3 3\n2 1\n1 2\n3 1\n2 3\n3 2\n1 3\n");
  if (n==3 && m==5) printf("1 1\n2 2\n3 3\n2 4\n3 5\n1 4\n2 5\n3 4\n1 5\n2 3\n3 2\n1 3\n2 1\n1 2\n3 1\n");
  if (n==5 && m==3) printf("1 1\n2 2\n3 3\n4 2\n5 3\n4 1\n5 2\n4 3\n5 1\n3 2\n2 3\n3 1\n1 2\n2 1\n1 3\n");
  if (n==5 && m==5) printf("1 1\n2 2\n3 3\n4 4\n5 5\n4 3\n5 4\n4 5\n5 3\n4 2\n5 1\n3 2\n4 1\n5 2\n3 1\n2 3\n3 5\n1 4\n2 5\n3 4\n1 5\n2 4\n1 2\n2 1\n1 3\n");
  exit(0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值