Analysis
有点妙嘞。好题?
每一行,每一列分别看作一个点
同一个点的行列相连边
显然会得到一个二分图
而对于染色操作,等价于给每条边定向
最后要求满足每个点的出入度之差<=1
(是不是和今天这道考试题WOJ#4761有点像呢?只是变简单了,只有边权为1的情况)
这个情况怎么分配来满足呢?
考虑到欧拉回路的性质
每个点的出度==入度
我们就将原图变作欧拉回路,跑一跑即可
(也就是将度数为奇数的点,两两相连。)
注意:即使增加了这些边后,新图可能还是不联通,所以我们需要将每一个点代进去算一遍
(毕竟我们只是选择了相邻的两点连接)
正确性?
由于度数为奇数的点只可能有偶数个,所以我们相邻两个连接在一起
每个点最多被增加一条边
在跑完欧拉回路后,删去这些添加的边,仍然可以满足题目限制
为什么只有偶数个呢?
考虑每增加一条边,总度数+=2.所以总度数始终为偶数
Code
#include<bits/stdc++.h>
#define in read()
#define re register
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
const int N=2e5+10;
int n,du[N<<2];
int nxt[N<<2],head[N<<2],to[N<<2],ecnt=1;
inline void add(int x,int y){
nxt[++ecnt]=head[x];head[x]=ecnt;to[ecnt]=y;
}
int vis[N<<2];
void dfs(int u){
for(re int &e=head[u];e;e=nxt[e]){
int v=to[e];
if(vis[e]||vis[e^1]) continue;
vis[e]=1;dfs(v);
}
}
int main(){
n=in;
for(re int i=1;i<=n;++i){
int x=in,y=in;y+=2e5;
add(x,y);add(y,x);
du[x]++;du[y]++;
}
int last=0;
for(re int i=1;i<=4e5;++i){
if(du[i]&1){
if(last) add(last,i),add(i,last),last=0;
else last=i;
}
}
//
for(re int i=1;i<=4e5;++i) if(du[i])dfs(i);
for(re int i=1;i<=n;++i) {
if(vis[i<<1]) printf("%c",'b');
else printf("%c",'r');
}
return 0;
}
然后如果用今天T3的方法也照样A
#include <bits/stdc++.h>
template <typename _tp> inline void read(_tp&x){
char ch=getchar(),ob=0;x=0;
while(ch!='-'&&!isdigit(ch))ch=getchar();if(ch=='-')ob=1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();if(ob)x=-x;
}
const int N = 4e5, M = N + N;
int dir[2][N];
int rev[M], ans[M], rep[M];
int vis[N];
int n,tot;
struct node {
int id, to;
}a[2][N];
void add(int x, int y, int id, int t) {
node*f = a[t];
int*d = dir[t];
if(f[x].id and f[x].to == y) {
rep[f[x].id] = rep[id] = 0;
ans[id] = 1, ans[f[x].id] = d[y];
f[x].id = f[y].id = 0;
return ;
}
bool flg = true;
if(f[x].id) {
flg = false;
rep[f[x].id] = tot;
rev[f[x].id] = d[x];
f[x].id = 0;
x = f[x].to;
}
if(f[y].id) {
flg = false;
rep[f[y].id] = tot;
rev[f[y].id] = d[y] ^ 1;
f[y].id = 0;
y = f[y].to;
}
f[x].to = y, f[y].to = x;
d[x] = 1, d[y] = 0;
if(flg) f[x].id = f[y].id = id;
else rep[id] = f[x].id = f[y].id = tot++;
}
void work(int p) {
int x = p, t = 0;
vis[x] = 1;
while(a[t][x].id) {
ans[a[t][x].id] = dir[t][x];
if(vis[a[t][x].to]) return ;
vis[a[t][x].to] = true;
x = a[t][x].to, t ^= 1;
}
x = p, t = 1;
while(a[t][x].id) {
ans[a[t][x].id] = dir[t][x] ^ 1;
vis[a[t][x].to] = true;
x = a[t][x].to, t ^= 1;
}
}
int main() {
read(n);tot=n+1;
for(int i=1,x,y,z;i<=n;++i) {
read(x);read(y);y+=2e5;
add(x, y, i,0);
}
for(int i=1;i<=4e5;++i)
if(!vis[i]) work(i);
for(int i=tot;i;--i)
if(rep[i]) ans[i] = ans[rep[i]] ^ rev[i];
for(int i=1;i<=n;++i){
if(ans[i]) printf("%c",'b');
else printf("%c",'r');
}
return 0;
}