ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022 Winter Team Contest - 1-D(二分图最大匹配)

2022-01-17 23:02:28  阅读:181  来源: 互联网

标签:二分 Contest int gp vis 2022 Team find match


PDF

D - Swap Free
在这里插入图片描述
在这里插入图片描述

大意:
给你n个字符串,长度相等,字符串之间没有重复,单个字符串内的字符也不重复,可以对字符串执行一种操作,操作就是任意选两个字符交换位置,如果无法将集合中的任何单词转换为集合中的任何其他单词,则一组单词称为无交换,让你求最大无交换集

    可以把他们每个字符串看成图的点,他们之间的(无交换)关系看作边,
集合中任意两个字符串都符合这个关系就可以看成一个完全图,所以我们要找这个最大的完全图

一个图的最大完全图等于它的补图的最大独立集
最大独立集=顶点数-最小点覆盖
这个图的点需要经过偶数次交换才能回到自身,所以是个二分图
二分图的最小点覆盖等于=最大匹配数
所以问题就转化为求图的最大匹配问题

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n;
string str[555];
vector<int>ma[555];
int vis[555];
int match[555];
int ans;

bool find(int x) { ///找最大匹配
	int len=ma[x].size();
	for(int i=0; i<len; i++) {
		if(!vis[ma[x][i]]) {
			vis[ma[x][i]] = 1;
			if(!match[ma[x][i]]||find(match[ma[x][i]])) {
				match[ma[x][i]] = x;
				return 1;
			}
		}
	}
	return 0;
}
int main() {
	scanf("%d",&n);
	for(int i=1; i<=n; i++) {
		cin>>str[i];
	}
	int len=str[1].length();
	for(int i=1; i<=n; i++) {
		for(int j=i+1; j<=n; j++) {
			int num=0;
			for(int k=0; k<=len; k++) {
				if(str[i][k]!=str[j][k])
					num++;
				if(num>2)
					break;
			}
			if(num==2) { ///只有两个交换
				ma[i].push_back(j);
				ma[j].push_back(i);
			}
		}
	}
///二分图的最大独立集等于图中点的个数 - 最大匹配数。
	ans=0;
	for(int i=1; i<=n; i++) {
		memset(vis,0,sizeof(vis));
		if(find(i)) ans++;
	}
	cout<<n-ans/2<<endl;
	return 0;
}

来个小小变形题

Asteroids
大意:给你一个n*n的矩阵,图上给你k个‘X’,有个炸弹能一次炸掉一行一列,问你最少炸几次能炸完.
在这里插入图片描述
把行坐标,列坐标,抽象成二分图的左半边,右半边,行列坐标的交点如果有’x’就连成一条边,想要把’x’炸完,就是把边去掉,也就是问你最少删除几个顶点,能把所有的边删除,解决这种问题就是最小点覆盖问题,又因为行和行之间不可能有边,同理列也不可能有边,所以这个图也是个二分图,由二分图的最小点覆盖等于=最大匹配数可知,这个题就是让求最大匹配数的.

#include<string.h>
#include<iostream>
using namespace std;
const int N=555,M=N*N;
int n,k;
bool gp[N][N];
bool vis[N];
int match[N];
bool find(int u){
	for(int i=1;i<=n;i++){
		if(!vis[i]&&gp[u][i]){
			vis[i]=1;
			if(!match[i]||find(match[i])){
				match[i]=u;
				return 1;
			}
		}
	}
	return 0;
}

int main(){
	ios::sync_with_stdio(false);
    cin.tie(0);  cout.tie(0);
    
	cin>>n>>k;
	int a,b;
	for(int i=1;i<=k;i++){
		cin>>a>>b;
		gp[a][b]=1;
	}
	
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof vis);
		ans+=find(i);
	}
	cout<<ans;
}

感觉不够?那就再来个
A - Fire Net
虽然是vj上的,但是题源在航电那··· ···交不了了

大意:给你一个n*n的矩阵,矩阵由’.‘和’X’组成,’.‘可以放大炮,可以往上下左右发射炮弹,这个’X’是墙,炮弹打不透这个墙,问你最多可以放多少门炮在’.'上,让他们互相打不到;

思路:
首先处理这个烦人的墙:
只看行,某一行在有墙阻挡的时候,能放多个炮台
这个墙就把行分成了多个可以放一个炮台的’子行’
同理,列一样
现在这些新的子行,子列就可以任意配对,转化为八皇后问题了
然后用匈牙利算法,把行当作二分图的左边的点,列当作二分图的右边的点
行和列的最大交点数,也就是二分图的最大匹配数就算出来了

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100,M=N*N;

int n,ans;
int nu,nv;
int newgp[N][N];
int match[N];
bool vis[N];

char gp[N][N];
struct node {
	int u,v;
} a[N][N];


bool find(int u) {
	for(int i=1;i<=nv;i++){
		if(!vis[i]&&newgp[u][i]){
			vis[i]=1;
			if(match[i]==0||find(match[i])){
				match[i]=u;
				return 1;
			}
		}
	}
	return 0;
}

void init() {
	ans=0;
	nu=nv=1;
	memset(match,0,sizeof match);
	memset(a,0,sizeof a);
	memset(newgp,0,sizeof newgp);
	memset(vis,0,sizeof vis);
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);

	while(cin>>n,n) {
		init();
		for(int i=1; i<=n; i++) {
			cin>>gp[i]+1;
		}
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=n; j++) {
				if(gp[i][j]=='.') {
					if(j==1||gp[i][j-1]=='X') nu++;
					a[i][j].u=nu;
				}
				if(gp[j][i]=='.') {
					if(i==1||gp[j-1][i]=='X') nv++;
					a[j][i].v=nu;
				}
			}
		}
		for(int i=1; i<=n; i++) {
			for(int j=1; j<=n; j++) {
				if(gp[i][j]=='.') {
					int u=a[i][j].u;
					int v=a[i][j].v;
					newgp[u][v]=1;
				}
			}
		}
		for(int i=1;i<=nu;i++){
			memset(vis,0,sizeof vis);
			if(find(i)) ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

标签:二分,Contest,int,gp,vis,2022,Team,find,match
来源: https://blog.csdn.net/li3124992092/article/details/122548928

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有