GYM102268 Angle Beats(一般图匹配)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GYM102268 Angle Beats(一般图匹配)相关的知识,希望对你有一定的参考价值。

GYM102268 Angle Beats(一般图匹配)

给定 n × m n\\times m n×m矩阵

一个+能与四周两个.匹配,一个*只能与两个.围成为 L L L型,即这两个.共一个顶点。输出最多匹配的方案。

考虑拆点,把+,*拆两个点,然后+ 的两个点与四周的.连边,把* 的两个点分别连上左右和上下的.,这样保证*的两个点有匹配时 一定是匹配L

然后就是输出方案,如果对于.或者*,如果两个点均有匹配,且匹配不是他们两个,就染色,染色注意判四周是否已经染过色了,选用一个没用的字母即可。

时间复杂度: O ( n m ) O(nm) O(nm) 这里 n , m n,m n,m 是实际结点和实际边数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5,M=105,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
#define mst(a,b) memset(a,b,sizeof a)
struct Blossom_Tree
    vector<int>e[N];
    queue<int>q;
    int mh[N],pre[N],s[N],id[N],vis[N],n,num;
    void init(int nn)	//初始化 
        n=nn,num=0;
        for(int i=1;i<=n;i++) e[i].clear(),mh[i]=pre[i]=vis[i]=s[i]=id[i]=0;
    
    void add(int u,int v)
        e[u].push_back(v),e[v].push_back(u);
    
    int find(int x) return s[x]==x?x:s[x]=find(s[x]);
    int LCA(int x,int y)	//求LCA. 
    for(++num;;swap(x,y))
        if(x)
        if(id[x=find(x)]==num) return x;//在同一个奇环肯定能找到被编号的结点. 
        id[x]=num,x=pre[mh[x]];	//沿增广路径的非匹配边向上走直到找到祖先. 
    
    
    void blossom(int x,int y,int rt)	//缩点(开花)  O(n)
        while(find(x)!=rt)
            pre[x]=y,y=mh[x];
            if(vis[y]==2) vis[y]=1,q.push(y);//如果奇环上有2型结点 就变为1型结点加入队列. 
            if(find(x)==x) s[x]=rt;//只对根处理. 
            if(find(y)==y) s[y]=rt;
            x=pre[y];
        
    
    bool aug(int st)	//求增广路径.O(n) 
    for(int i=1;i<=n;i++) vis[i]=pre[i]=0,s[i]=i; 
    while(!q.empty()) q.pop();
    q.push(st),vis[st]=1;
    while(!q.empty())
        int u=q.front();q.pop();
        for(auto v:e[u])
            if(find(u)==find(v)||vis[v]==2) continue;//如果是已经缩点了或者是偶环直接继续,没有影响. 
            if(!vis[v])	//如果没有被染色 
                vis[v]=2,pre[v]=u;
                if(!mh[v])	//如果未被匹配,就进行匹配 
                    for(int x=v,last;x;x=last)	//增广路取反 
                        last=mh[pre[x]],mh[x]=pre[x],mh[pre[x]]=x;
                    return 1;
                
                vis[mh[v]]=1,q.push(mh[v]); //否则将v的匹配结点染色,加入队列. 
            
            else
             int rt=LCA(u,v);	//找到LCA ,然后进行缩点. 
             blossom(u,v,rt),blossom(v,u,rt);
            
        
    
    return 0;
    
    void cal()
        int ans=0;
        for(int i=1;i<=n;i++) if(!mh[i]&&aug(i)) ans++;	//最大匹配. 
       // return ans;
       //printf("ans=%d\\n",ans);
    
T;
int n,m;
char a[M][M];
int c1[M][M],c2[M][M];
int dir[4][2]=0,1,0,-1,1,0,-1,0;
bool used[26];
void color(int x,int y)
	for(int i=0;i<4;i++)
		int nx=x+dir[i][0],ny=y+dir[i][1];
		if(a[nx][ny]>='a'&&a[nx][ny]<='z') used[a[nx][ny]-'a']=true;
	

char get_chr(int x,int y)
	mst(used,0);
	color(x,y);
	for(int i=0;i<4;i++)
		int nx=x+dir[i][0],ny=y+dir[i][1];
		if(T.mh[c1[x][y]]==c1[nx][ny]||T.mh[c2[x][y]]==c1[nx][ny]) 
			color(nx,ny);
		
	
	for(int i=0;i<26;i++) if(!used[i]) return i+'a';

void solve()
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]=='+'||a[i][j]=='*')
		if(T.mh[c1[i][j]]==c2[i][j]||!T.mh[c2[i][j]]||!T.mh[c1[i][j]])
			continue;
		
		char ch = get_chr(i,j);
		a[i][j]=ch;
		for(int k=0;k<4;k++)
			int nx=i+dir[k][0],ny=j+dir[k][1];
			if(T.mh[c1[nx][ny]]==c1[i][j]||T.mh[c1[nx][ny]]==c2[i][j])
				a[nx][ny]=ch;
			
		
			
		
	
	for(int i=1;i<=n;i++) printf("%s\\n",a[i]+1);

int main()
	scanf("%d%d",&n,&m);
	int sz=0;
	for(int i=1;i<=n;i++)
		scanf("%s",a[i]+1);
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]=='.') c1[i][j]=++sz;
			else c1[i][j]=++sz,c2[i][j]=++sz,T.add(sz-1,sz);
		
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			if(a[i][j]=='*')
				if(a[i][j-1]=='.') T.add(c1[i][j],c1[i][j-1]);
				if(a[i][j+1]=='.') T.add(c1[i][j],c1[i][j+1]);
				if(a[i-1][j]=='.') T.add(c2[i][j],c1[i-1][j]);
				if(a[i+1][j]=='.') T.add(c2[i][j],c1[i+1][j]);
			else if(a[i][j]=='+')
				for(int k=0;k<4;k++)
					int x=i+dir[k][0],y=j+dir[k][1];
					if(a[x][y]=='.') 
					T.add(c1[i][j],c1[x][y]),T.add(c2[i][j],c1[x][y]);		
				
			
		
	T.n=sz;
	T.cal();
	solve();
    return 0;



以上是关于GYM102268 Angle Beats(一般图匹配)的主要内容,如果未能解决你的问题,请参考以下文章

Gym102361A Angle Beats(直角三角形 计算几何)题解

CCPC秦皇岛gym102361A. Angle Beats

CCPC秦皇岛gym102361A. Angle Beats

CCPC秦皇岛gym102361A. Angle Beats

Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

Gym102268D Dates