UVA 11419 SAM I AM (最小点覆盖)

二分图匹配的题目,属于二分图的顶点覆盖问题。
题目有点像之前做过的一道星际陨石的题目。


题目大概的意思是说,给你一个地图,图上有些点上有东西。
现在我有几门大炮,可以放在某一行或者某一列,然后这一行这一列的东西就会被打掉。
现在要求开炮的次数最小,然后输出开炮方案。
如果这道题目只叫你输出开炮的次数,那很简单,套一下二分图匹配的模板就可以过了。
但这道题目还要输出开炮方案,即是输出二分图匹配顶点覆盖选了那几个顶点。

首先题目用二分图匹配做,使用匈牙利算法找增广路
当匹配完以后,我们在跑一次匈牙利算法
(行为点集X,列为点集Y,在地图上的点抽象为连接点集X和点集Y的线)
这个时候已经是满匹配的状态,不可能在找到增广路
首先我们先假定只在行放大炮,有些正解应该在列也放大炮
那么我们什么时候在列放大炮呢?这个问题需要我们解决。
这个问题最后转换为最小顶点覆盖问题,即选择最少的点把所有的边覆盖。
上面我们已经选择了部分行放大炮,把与这些点相连的线删去
这时候我们在看以下这边的线情况,如果没有线剩下,那么就达到目的,是正解。
如果还有线剩下,那说明我们应该在列放一些炮。
剩下的点都是在找增广路中没有匹配的点,要么是孤立的点,没有线相连
要么是在增广过程中,匹配给别人。要消除这样的点的线,就需要在对应的点集Y放炮
而如果在Y放炮,与这个Y相连的线可能会重合,这样既有浪费。
所有把从这个点Y出发的X点标记(不会放炮的位置),这样就能最高效的利用。
最后根据这个标记结果,就可以输出正确答案


题解写的有点冗余,还是能看懂。模拟两次会理解的更加清楚


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
#define maxn 1005
using namespace std;
int r,c,k;
int visx[maxn],visy[maxn];
int cx[maxn],cy[maxn];
int maps[maxn][maxn];
int match[maxn];
int dfs(int x)//DFS增广
{
	visx[x]=1;
	for(int y=1;y<=c;y++)
	{
		if(maps[x][y]&&!visy[y])
		{
			visy[y]=1;
			if(cy[y]==0||dfs(cy[y]))
			{
				cx[x]=y;
				cy[y]=x;
				return 1;
			}
		}
	}
	return 0;
}

int MaxMatch()
{
	int sum=0;
	memset(cx,0,sizeof cx);
	memset(cy,0,sizeof cy);
	for(int i=1;i<=r;i++)
	{
		memset(visx,0,sizeof visx);
		memset(visy,0,sizeof visy);
		sum+=dfs(i);
	}
	return sum;
}
void init()
{
	memset(maps,0,sizeof maps);
	memset(visx,0,sizeof visx);
	memset(visy,0,sizeof visy);
	memset(cx,0,sizeof cx);
	memset(cy,0,sizeof cy);
}
int main()
{
	int i,a,b;
	while(scanf("%d%d%d",&r,&c,&k)!=EOF)
	{
		init();
		if(r==0&&c==0&&k==0)
			break;
		for(i=1;i<=k;i++)
		{
			scanf("%d%d",&a,&b);
			maps[a][b]=1;
		}
		int ans=MaxMatch();
		printf("%d",ans);
		memset(visx,0,sizeof visx);
		memset(visy,0,sizeof visy);
		for ( i = 1; i <= r; i++)//找最小顶点
            if (cx[i]== 0)
                dfs(i);
		for(i=1;i<=r;i++)
			if(!visx[i])
				printf(" r%d",i);
		for(i=1;i<=c;i++)
			if(visy[i])
				printf(" c%d",i);
		cout<<endl;

	}
}





全部评论

相关推荐

会飞的猿:我看你想进大厂,我给你总结一下学习路线吧,java语言方面常规八股要熟,那些java的集合,重点背hashmap八股吧,jvm类加载机制,运行时分区,垃圾回收算法,垃圾回收器CMS、G1这些,各种乐观锁悲观锁,线程安全,threadlocal这些。在进阶一些的比如jvm参数,内存溢出泄漏排查,jvm调优。我这里说的只是冰山一角,详细八股可以去网上找,这不用去买,都免费资源。mysql、redis可以去看小林coding,我看你简历上写了,你一定要熟,什么底层b+树、索引结构、innodb、mvcc、undo log、redo log、行级锁表级锁,这些东西高频出现,如果面试官问我这些我都能笑出来。消息队列rabbitmq也好kafka也好,学一种就行,什么分区啊副本啊确认机制啊怎么保证不重复消费、怎么保证消息不丢失这些基本的一定要会,进阶一点的比如LEO、高水位线、kafka和rocketmq底层零拷贝的区别等等。计算机网络和操作系统既然你是科班应该理解起来问题不大,去看小林coding这两块吧,深度够了。spring boot的八股好好看看吧,一般字节腾讯不这么问,其他的java大厂挺爱问的,什么循环依赖啥的去网上看看。数据结构的话科班应该问题不大,多去力扣集中突击刷题吧。项目的话其实说白了还是结合八股来,想一想你写的这些技术会给你挖什么坑。除此之外,还有场景题、rpc、设计模式、linux命令、ddd等。不会的就别往简历上写了,虽然技术栈很多的话好看些,但背起来确实累。总结一下,多去实习吧,多跳槽,直到跳到一个不错的中厂做跳板,这是一条可行的进大厂的路线。另外,只想找个小厂的工作的话,没必要全都照这些准备,太累了,重点放在框架的使用和一些基础八股吧。大致路线就这样,没啥太多难度,就是量大,你能达到什么高度取决于你对自己多狠,祝好。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务