【题解】[POI 2019] Układ scalony
给定一个 \(n\times m\) 的网格图,生成一颗直径为 \(k\) 的树。
首先不难得到一个粗略的上下界。直径不可能超过 \(n\times m -1\) ,不可能小于 \(n+m-2\) 。
但是手算一下 \(2\times 2\) ,\(2\times 4\) 之类的网格,发现也无法构造出直径为 \(n+m-2\) 的树。
对于 \(n,m\) 中有一个为奇数的情况,我们可以找出中间行/列,其余所有点向中间行/列方向连边,可以得到一颗直径为 \(n+m-2\) 的树,同时这也是下界。
对于 \(n,m\) 都是偶数,取 \(\left\lfloor\dfrac{n}{2}\right\rfloor\) 行为中间行,其余点向中间行方向连边,可以得到一颗直径为 \(n+m-1\) 的树,同时这也是下界。
对于 \(n,m\) 中有一个奇数的情况,我们取 \((1,1)\),\((n,m)\) 为直径的两端,每次从两端向外扩展一格,可以得到所有直径长度在 \([n+m-2,n\times m-1]\) 之间的树。
对于 \(n,m\) 均为偶数的情况,我们将 \((1,1)\) 与 \((1,2)\) 连边,发现直径仍然是 \(n+m-1\) ,然后以 \((1,2)\) ,\((n,m)\) 为直径的两端,每次向外扩展一格,可以得到所有直径长度在 \([n+m-1,n\times m-1]\) 之间的树。
但是当 \(n=2\) 时 \((1,1)\) 和 \((1,2)\) 同时属于中间行,这种构造方法行不通。
我们稍作修改,\(n=2\) 而 \(m!=2\) 时,我们可以交换 \(n,m\) 使之成为 \(n!=2\) 的情况。而 \(n=m=2\) 时,只有 \(k=3\) 时有解,特判一下即可。
时间复杂度 \(\mathcal{O}(nm)\) 。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 1005
using namespace std;
int n,m,k,op,v[N][N];
namespace task1{
typedef pair<int,int> Pr;
#define F first
#define S second
vector<pair<Pr,Pr> >a;
void ins(int x,int y,int p,int q){
a.push_back(make_pair(make_pair(x,y),make_pair(p,q)));
}
void main(){
if(k<n+m-2||k>=n*m){puts("NIE");return ;}
puts("TAK");
int cen=(n+1)/2;
rep(i,1,m-1)ins(cen,i,cen,i+1);
rep(i,1,cen-1)ins(i,1,i+1,1),v[i][1]=1;
rep(i,cen+1,n)ins(i,m,i-1,m),v[i][m]=1;
int x=1,y=1,tp=0;k-=n+m-2;int w=min(k,(cen-1)*(m-1));
rep(i,1,w){
k--;
if(tp==0&&y==m)ins(x,y,x+1,y),tp=1,x++;
else if(tp==1&&y==2)ins(x,y,x+1,y),tp=0,x++;
else if(tp==0)ins(x,y,x,y+1),y++;
else ins(x,y,x,y-1),y--;
v[x][y]=1;
}
rep(i,1,m)v[cen][i]=1;
x=n,y=m,tp=0;w=min(k,(cen-1)*(m-1));
rep(i,1,w){
k--;
if(tp==0&&y==1)ins(x,y,x-1,y),tp=1,x--;
else if(tp==1&&y==m-1)ins(x,y,x-1,y),tp=0,x--;
else if(tp==0)ins(x,y,x,y-1),y--;
else ins(x,y,x,y+1),y++;
v[x][y]=1;
}
rep(i,1,n)rep(j,1,m)if(!v[i][j]){
if(i>cen)ins(i,j,i-1,j);
else ins(i,j,i+1,j);
}
rep(i,0,n*m-2){
if(op)printf("%d %d %d %d\n",a[i].F.S,a[i].F.F,a[i].S.S,a[i].S.F);
else printf("%d %d %d %d\n",a[i].F.F,a[i].F.S,a[i].S.F,a[i].S.S);
}
}
}
namespace task2{
typedef pair<int,int> Pr;
#define F first
#define S second
vector<pair<Pr,Pr> >a;
void ins(int x,int y,int p,int q){
a.push_back(make_pair(make_pair(x,y),make_pair(p,q)));
}
void main(){
if(n==2&&m==2){
if(k!=3){puts("NIE");return;}
printf("TAK\n1 1 1 2\n1 1 2 1\n2 2 1 2\n");
return ;
}
if(n<m)swap(n,m),op^=1;
if(k<n+m-1||k>=n*m){puts("NIE");return ;}
puts("TAK");
int cen=n/2;
rep(i,1,m)v[cen][i]=1;
rep(i,1,m-1)ins(cen,i,cen,i+1);
rep(i,1,cen-1)ins(i,1,i+1,1),v[i][1]=1;
rep(i,cen+1,n)ins(i,m,i-1,m),v[i][m]=1;
v[1][2]=1;ins(1,1,1,2);
int x=1,y=2,tp=0;k-=n+m-1;int w=min(k,(cen-1)*(m-1)-1);
rep(i,1,w){
k--;
if(tp==0&&y==m)ins(x,y,x+1,y),tp=1,x++;
else if(tp==1&&y==2)ins(x,y,x+1,y),tp=0,x++;
else if(tp==0)ins(x,y,x,y+1),y++;
else ins(x,y,x,y-1),y--;
v[x][y]=1;
}
x=n,y=m,tp=0;w=min(k,cen*(m-1));
rep(i,1,w){
k--;
if(tp==0&&y==1)ins(x,y,x-1,y),tp=1,x--;
else if(tp==1&&y==m-1)ins(x,y,x-1,y),tp=0,x--;
else if(tp==0)ins(x,y,x,y-1),y--;
else ins(x,y,x,y+1),y++;
v[x][y]=1;
}
rep(i,1,n)rep(j,1,m)if(!v[i][j]){
if(i>cen)ins(i,j,i-1,j);
else ins(i,j,i+1,j);
}
rep(i,0,n*m-2){
if(op)printf("%d %d %d %d\n",a[i].F.S,a[i].F.F,a[i].S.S,a[i].S.F);
else printf("%d %d %d %d\n",a[i].F.F,a[i].F.S,a[i].S.F,a[i].S.S);
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
if(m&1)swap(n,m),op=1;
if(n&1)task1::main();
else task2::main();
return 0;
}