• Topcoder SRM568 Div1 DisjointSemicircles (二分图染色)


    Topcoder SRM568 Div1 DisjointSemicircles (二分图染色)

    题意: 给定数轴上排列的(2n)个点,每个点需要找到另一个点和它匹配,并且以他们为直径两端,向上或者向下作一个半圆

    有一些点已经匹配好了,要求判断是否存在一个合法的方案,满足所有的半圆不相交

    思路:

    枚举已经确定的匹配半圆的方向(设有(m)对已匹配),然后(O(n))判断自由点是否存在合法方案

    判断合法方案的核心性质:

    定义一个点的方向为其所连接的半圆的方向(上为0,下为1)

    则自由点存在合法方案的充要条件是:

    整个序列上每种方向的点数为偶数,且所有已匹配的半圆所覆盖的区间下,和半圆同向的点个数为偶数

    必要性:

    如果某个半圆下同向点个数为奇数,则必然有一个点与其同向并且不得不连到区间外,这显然不合法

    充分性:

    一种合法的构造方法是:

    按照(L)从左到右,遍历每个已匹配的半圆,如果包含同向子半圆优先解决同向的子半圆

    剩下的点依然是偶数个,从左到右依次和上一个匹配即可

    [ ]

    判断是否存在合法方案

    那么问题转化为判断是否存在一种合法的定向方案,使得某一些区间里0/1的个数为偶数

    考虑构建二分图染色,令点集(V={0,1,cdots,n,0',1',cdots,n'}),则((u,v)in E)表示(col(u) e col(v))

    其中(i)号节点表示(1-i)中所有未匹配节点方向的异或和,(i')表示(i)的反点((i,i')in E)

    (到这里可以自己想一下怎么连边)

    对于已匹配圆([L,R]) (注意不要忘了([1,n]))

    如果它方向为(1),显然只需要(col(L-1)=col(R))

    如果方向为0,设([L,R])未染色个数为(k),则显然有(col(L-1)=col(R)oplus (kmod 2)),即考虑反向的个数

    同时对于已匹配点(i),显然有(col(i)=col(i-1))

    由此,得到一个(O(n))点数边数的图

    如果在( ext{dfs})枚举时同步加边和回撤,总复杂度就为(O(2^mcdot n))

    由于不可能所有方案都合法,实际应该是一个比较松的上界

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    
    const int N=110;
    
    int n;
    int a[N];
    int cnt[N];
    int L[N],R[N],m,Cross[N][N];
    int vec[2][N],c[2];
    
    struct Edge{
    	int u,v,nxt;
    }e[N*10];
    int head[N],ecnt;
    void AddEdge(int u,int v) {
    	e[++ecnt]=(Edge){u,v,head[u]};
    	head[u]=ecnt;
    }
    void Link(int u,int v){ 
    	AddEdge(u,v),AddEdge(v,u); 
    }
    void Back(){
    	head[e[ecnt].u]=e[ecnt].nxt,ecnt--;
    	head[e[ecnt].u]=e[ecnt].nxt,ecnt--;
    }
    
    int ans,fl;
    int vis[N];
    void dfs_col(int u,int c){
    	vis[u]=c;
    	for(int i=head[u];i;i=e[i].nxt){
    		int v=e[i].v;
    		if(!vis[v]) dfs_col(v,3-c);
    		else if(vis[v]==vis[u]) fl=0;
    	}
    }
    
    void dfs(int p) {
    	if(ans) return;
    	if(p>m){
    		rep(i,0,n*2+1) vis[i]=0;
    		fl=1;
    		rep(i,0,n*2+1) if(!vis[i]) dfs_col(i,1);
    		ans|=fl;
    		return;
    	}
    	rep(i,0,1){
    		int fl=1;
    		rep(j,1,c[i]) if(R[vec[i][j]]>L[p] && R[vec[i][j]]<R[p]) fl=0;
    		if(!fl) continue;
    		vec[i][++c[i]]=p;
    		if(i || ~(cnt[R[p]]-cnt[L[p]])&1) Link(L[p]+n+1,R[p]-1);
    		else Link(L[p],R[p]-1);
    		dfs(p+1);
    		c[i]--,Back();
    	}
    }
    
    class DisjointSemicircles {
    public:
    	string getPossibility(vector <int> labels) {
    		n=labels.size(),m=0;
    		rep(i,1,n) a[i]=labels[i-1];
    		rep(i,1,n) {
    			cnt[i]=cnt[i-1]+(a[i]==-1);
    			if(~a[i]) rep(j,i+1,n) if(a[j]==a[i]) L[++m]=i,R[m]=j;
    		}
    		if(!m) return "POSSIBLE";
    		rep(i,0,(n+1)*2) head[i]=ecnt=0;
    		rep(i,1,n) if(~a[i]) Link(i+n+1,i-1);
    		rep(i,0,n) Link(i,i+n+1);
    		Link(n+1,n);
    		ans=0,dfs(1);
    		return ans?"POSSIBLE":"IMPOSSIBLE";
    	}
    };
    
    
    
  • 相关阅读:
    Selenium入门15 截图
    selenium入门14 窗口切换
    Locust的官网及安装
    命令行输入Jmeter提示不是内部或外部命令,处理方式:添加环境变量
    python pip安装报错python setup.py egg_info failed with error code 1
    Selenium入门13 cookie的增删改查
    Selenium入门12 鼠标和键盘事件
    Selenium入门11 滚动条控制(通过js)
    Selenium入门10 弹出框的处理 switch_to.alert
    Selenium入门9 上传文件
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13604292.html
Copyright © 2020-2023  润新知