CF547D Mike and Fish

传送门

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值