[GCJ 2019 #3] Datacenter Duplex 题解
这题很 6。
以下定义“边界”为满足
考虑如果最终某个颜色没有连通(不妨设为颜色
- 一个颜色
\text{B} 的环把\text{A} 分成了里面和外面,称为情况1 ; - 一个颜色
\text{B} 的路径把\text{A} 分成了两边(可以得出这条路径的两个端点均在边界上,并且路径上存在一些点不经过边界),称为情况2 。
注意到一个事情:如果用新建的走廊把两个已经连通的格子连起来必然没用;在之后的构造中不会去做这样的事情。这样就解决了情况
对于情况
于是考虑对于每个
放代码:
#include<bits/stdc++.h>
using namespace std;
namespace IAOI_lib{
template<typename T> class dsu{
private:
vector<T> a;
vector<int> s;
public:
dsu(int n=2e5){
a.resize(n),s.resize(n,1);
iota(a.begin(),a.end(),0);
}
T leader(T x){
return a[x]==x?x:a[x]=leader(a[x]);
}
inline int size(T x){
return s[leader(x)];
}
inline void merge(T x,T y){
x=leader(x),y=leader(y);
if(x==y)return;
if(s[x]>s[y])swap(x,y);
s[y]+=s[x],a[x]=y;
}
inline bool same(T x,T y){
return leader(x)==leader(y);
}
}; // 并查集模板
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int tt; cin>>tt;
for(int t=1;t<=tt;t++){
int n,m,c=0; cin>>n>>m;
vector<string> a(n);
for(auto &i:a)cin>>i;
IAOI_lib::dsu<int> d(n*m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(i&&a[i-1][j]==a[i][j])d.merge((i-1)*m+j,i*m+j);
if(j&&a[i][j-1]==a[i][j])d.merge(i*m+j-1,i*m+j);
} // 先把四联通的连起来
vector r(n-1,string(m-1,'.'));
for(int i=1;i<n;i++)
for(int j=1;j<m;j++){
if(a[i-1][j-1]==a[i][j]&&!d.same((i-1)*m+j-1,i*m+j))
d.merge((i-1)*m+j-1,i*m+j),r[i-1][j-1]='\\';
else if(a[i-1][j]==a[i][j-1]&&!d.same((i-1)*m+j,i*m+j-1))
d.merge((i-1)*m+j,i*m+j-1),r[i-1][j-1]='/';
} // 只要找到未连通的就连
for(int i=0;i<n*m;i++)
c+=d.leader(i)==i; // 计算连通块个数,判断是否合法
if(cout<<"Case #"<<t<<": ";c==2){
cout<<"POSSIBLE\n";
for(auto i:r)cout<<i<<'\n';
}
else cout<<"IMPOSSIBLE\n";
}
return 0;
}