CF547D Mike and Fish
题目分析
有头熊闲着没事干,犯强迫症,非要让任何一横行或一纵列红蓝鱼的不超过1(就是1,-1,0)。
算法分析
反正正解没想到,反正靠着自己的理解,瞎搞的。把所有有关联的点连到一棵树里(开两部分,一个是横行,一个纵列),如果这棵树有奇数个点,那肯定是富裕一个的,把这棵树连到0节点上,保证所有点的出度和入度相等(想一想为什么),好跑欧拉回路。注意,因为你建的只是把有关系的放到一起,所以有可能㪰毫无关系的,比如一个图可以分成两部分,第二部分在第一部分边缘,所以互不影响。所以需要判断一下即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=220000;
int n,m,k,p[N*4],num,h[N*4],f[N*4],top;
bool flag[N*4];
struct node{
int x,y,z;
}a[N];
struct node1{
int x,y,k,next;
bool flag;
}data[N*10];
void link(int x,int y){
++num;
data[num].x=x;
data[num].y=y;
data[num].k=num+1;
data[num].flag=true;
data[num].next=h[x];
h[x]=num;
++num;
data[num].x=y;
data[num].y=x;
data[num].k=num-1;
data[num].flag=true;
data[num].next=h[y];
h[y]=num;
}
bool cmp1(node q,node p){
if(q.x<p.x)return true;
if(q.x==p.x&&q.y<p.y)return true;
return false;
}
void sort1(){
sort(a+1,a+n+1,cmp1);
k=0;
for(int i=1;i<=n;i++){
if(a[i].x!=k){
k=a[i].x;
++m;
}
p[m]++;
link(a[i].z,m);
}
}
bool cmp2(node q,node p){
if(q.y<p.y)return true;
if(q.y==p.y&&q.x<p.x)return true;
return false;
}
void sort2(){
sort(a+1,a+n+1,cmp2);
k=0;
for(int i=1;i<=n;i++){
if(a[i].y!=k){
k=a[i].y;
++m;
}
p[m]++;
link(a[i].z+n,m);
}
}
void dfs1(int x) {
for (int &i = h[x]; i != -1 && i != 0; i = data[i].next) {
int y = data[i].y;
if (!data[i].flag) continue ;
data[i].flag = data[data[i].k].flag = 0;
if(data[i].y==x+n)f[x]=1;
if(data[i].y==x-n)f[x-n]=-1;
flag[x]=false;flag[data[i].y]=false;
dfs1(y);
}
}
int main(){
scanf("%d",&n);
if (n == 1) {
puts("r");
return 0;
}
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].z=i;
}
m=n*2;
sort1();
sort2();
for(int i=1;i<=m;i++)if(p[i]%2==1)link(0,i);
for(int i=1;i<=n;i++)link(i,i+n);
top=1;memset(flag,true,sizeof flag);
while(top!=n){
for(int i=top;i<=n;i++){
top=i;
if(flag[i])break;
}
flag[top]=false;
dfs1(top);
}
for(int i=1;i<=n;i++){
if(f[i]==1)printf("b");
else if (f[i] == -1) printf("r");
}
return 0;
}