大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。

19十一高端峰会——金华站 T2 图论

第二道构造题

不把金华考生当人系列。

题解OJ上有,这里不赘述

关键是此题代码如果写的好只需50行,写的不好可能要200行。

这里给出100行的丑陋代码(懒人必备STL vector,省了很多代码)

#include<bits/stdc++.h>
using namespace std;

#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))

const int inf=0x3f3f3f3f,N=1e3+10;

int n,f[N],du[N],tot;
char s[N][N];
bool g[N][N],e[N][N];
bool vis[N];
vector<int>blo[N];

void read(int &x){
	x=0;char c=getchar(),f=1;
	while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
	while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
	x*=f;
}
inline int find(int x){ return f[x]=f[x]==x?x:find(f[x]); }
void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx==fy) return;
	g[x][y]=g[y][x]=1;
	f[fx]=fy;
}

void dfs(int u){
	vis[u]=1;
	go(v,1,n){
		if(!g[u][v]||vis[v]) continue;
		dfs(v);
		if(du[v]&1){
			++du[v],++du[u];
			e[u][v]=e[v][u]=1;
		}
	}
}
void fail(){ puts("No"),exit(0); }
void suc(){
	puts("Yes");
	go(i,1,n){
		go(j,1,n)
			printf("%d",e[i][j]||s[i][j]);
		puts("");
	}
	exit(0);
}

void Dfs(int u){
	blo[tot].push_back(u);
	vis[u]=1;
	go(v,1,n)
		if((s[u][v]||e[u][v])&&!vis[v])
			Dfs(v);
}

int main(){
	//freopen("input.txt","r",stdin);
	read(n);
	go(i,1,n) scanf("%s",s[i]+1),f[i]=i;
	go(i,1,n) go(j,1,n) s[i][j]-='0';
	go(i,1,n) go(j,i+1,n) s[i][j]?++du[i],++du[j]:0;
	go(i,1,n) go(j,i+1,n) if(find(i)!=find(j)&&!s[i][j]) merge(i,j);
	//建出补图的最小生成树 
	go(i,1,n)
		if(!vis[i]){
			dfs(i);
			if(du[i]&1) fail();
		}
	mem(vis,0);
	go(i,1,n) if(!vis[i]) ++tot,Dfs(i);
	int x,y;
	if(tot==1) suc();
	else{
		if(tot>2){
			go(i,1,tot-1){
				x=blo[i][0],y=blo[i+1][0];
				e[x][y]=e[y][x]=1;
			}
			x=blo[1][0],y=blo[tot][0];
			e[x][y]=e[y][x]=1;
			suc();
		}
		else{
			if(blo[1].size()>blo[2].size()) swap(blo[1],blo[2]);
			if(blo[1].size()>1){
				go(i,0,1)
					go(j,0,1)
						e[blo[1][i]][blo[2][j]]=e[blo[2][j]][blo[1][i]]=1;
				suc();
			}
			else{
				x=blo[1][0];
				for(int k=0;k<blo[2].size();++k)
					for(int l=k+1;l<blo[2].size();++l){
						int i=blo[2][k],j=blo[2][l];
						if(!s[i][j]){
							e[i][j]^=1;e[j][i]^=1;
							e[x][i]=e[i][x]=e[x][j]=e[j][x]=1;
							suc();
						}
					}
			}
		}
	}
	fail();
	return 0;
}

然后是xuyuan大佬包含智慧的并查集代码,十分精妙,只需50行

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,cc,d[N],fa[N],sz[N],q[N],vis[N],e[N][N],g[N][N];char s[N][N];
int fnd(int x){return fa[x]==x?x:fa[x]=fnd(fa[x]);}
void dfs(int x)
{
	vis[x]=1;
	for(int y=1;y<=n;y++)if(!vis[y]&&!e[x][y])
	{
		dfs(y);
		if(d[y]&1){d[x]++;d[y]++;g[x][y]=g[y][x]=1;}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)e[i][j]=s[i][j]-'0',d[i]+=e[i][j];
	for(int i=1;i<=n;i++)fa[i]=i,sz[i]=1;
	for(int i=1;i<=n;i++)if(!vis[i])dfs(i);
	for(int i=1;i<=n;i++)if(d[i]&1){puts("No");return 0;}
	for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)if((e[i][j]||g[i][j])&&fnd(i)!=fnd(j)){int x=fnd(i),y=fnd(j);fa[x]=y;sz[y]+=sz[x];}
	for(int i=1;i<=n;i++)if(fa[i]==i)q[++cc]=i;
	if(cc>2){for(int i=1;i<=cc;i++){int x=q[i],y=q[i%cc+1];g[x][y]=g[y][x]=1;}}
	else if(cc==2)
	{
		int u=q[1],v=q[2],x=-1,y=-1;
		if(sz[v]==1)swap(u,v);
		if(sz[u]>=2)
		{
			for(int i=1;i<=n;i++)if(fnd(i)==u&&i!=u)x=i;
			for(int i=1;i<=n;i++)if(fnd(i)==v&&i!=v)y=i;
			g[u][v]=g[v][u]=g[u][y]=g[y][u]=g[x][v]=g[v][x]=g[x][y]=g[y][x]=1;
		}
		else
		{
			for(int i=1;i<=n;i++)if(i!=u)for(int j=i+1;j<=n;j++)if(j!=u&&!e[i][j]){x=i;y=j;}
			if(x==-1){puts("No");return 0;}
			g[x][y]^=1;g[y][x]^=1;g[u][x]=g[x][u]=g[u][y]=g[y][u]=1;
		}
	}
	puts("Yes");
	for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)putchar((e[i][j]||g[i][j])?'1':'0');puts("");}
	return 0;
}
posted @ 2019-10-11 11:48  White_star  阅读(145)  评论(0编辑  收藏  举报
}