CodeForces - 1288D Minimax Problem(二分+状态压缩)

题目链接:点击查看

题目大意:给出一个n*m的矩阵,我们用maze[n][m]来表示每一个元素,现在我们需要选出其中 i 和 j 两行,i 和 j 可以相同,用这两行的元素构成一个新的数组a,构造规则为a[k]=max(maze[i][k],maze[j][k]),现在我们要使数组a中的最小值最大,请问该如何选择 i 和 j 才能满足条件

题目分析:读完题目后感觉乱糟糟的,但静下心来分析一下,要求最小值的最大值,显然的二分,所以我们很直接的确定下来要对于数组a的最小值进行二分了,但check函数该怎么写是我们接下来需要考虑的问题了,其实当我们确定下来了最小值之后,就相当于对原矩阵构成了一种约束条件,换句话说,原矩阵中值小于当前限制的元素,我们是无法选择的了,不然最后构成的数组a中的最小值就无法保证为当前二分的答案了,有了这样一个转换后,我们就可以将原矩阵中大于当前二分的答案的位置都置为1,其余位置置为0,这样就很自然的进行了状态压缩,因为每一行的元素都是绑定的,也就是对于某一行来说,我们只能选择或者不选,这样又是一种标准的枚举子集,我们再看一眼数据范围,发现m最大只有7,我们如果以枚举子集的形式来确定 i 和 j 的话,时间复杂度最大也只有2^14,所以我们可以直接两层for循环枚举子集状态,找到一种 i 和 j 的情况,满足其能覆盖整个子集就好了,具体实现看代码吧,代码写的比较清楚了

代码:

#include<iostream>
#include<cstdio> 
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;

typedef long long LL;

const int inf=0x3f3f3f3f;

const int N=3e5+100;

int a[N][8],vis[N],ans1,ans2,n,m;

bool check(int x)
{
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	{
		int val=0;
		for(int j=1;j<=m;j++)
			if(a[i][j]>=x)
				val|=1<<(j-1);//状态压缩
		vis[val]=i;//标记状态
	}
	for(int i=0;i<(1<<m);i++)//枚举i的状态
		if(vis[i])
			for(int j=0;j<(1<<m);j++)//枚举j的状态
				if(vis[j])
					if((i|j)==(1<<m)-1)
					{
						ans1=vis[i];
						ans2=vis[j];
						return true;
					}
	return false;
}

int main()
{
//	freopen("input.txt","r",stdin);
//	ios::sync_with_stdio(false);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	int l=0,r=inf;
	while(l<=r)//二分最小值
	{
		int mid=l+r>>1;
		if(check(mid))
			l=mid+1;
		else
			r=mid-1;
	}
	printf("%d %d\n",ans1,ans2);
	
	
	
	
	
	
	
	
	
	
	return 0;
}
发布了558 篇原创文章 · 获赞 16 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/104012920