时间: 2015.06.16
地点:厦门大学
简单题: 10个数字位取3个组成一个三位数(不能重复),使得这三位数的值最大。
方法:这个是送分题,我比较懒,直接用set 来存放,然后输出后面三个位置的值来搞定奇偶数排序问题
问题描述: 一串无序的数字,先根据所以奇数的逆序排序,再输出所有偶数的顺序排序数值。
方法: 很简单,基本两个排序就可以搞定。最大的边长问题:
问题描述:大致是这样子,有一个n*m的0 ,1 组成的矩阵,求该矩阵的最大的正方形子区域,使得正方形区域内的所有元素都为1,并输出改正方形的边长。其中n,m<=400;
解法1:暴力解法:穷尽所有的正方形子区域(O(N^2))+判断该正方形子区域内的元素是否都为1(O(N^2)),所以该方法的时间复杂度是(O(N^4)),鉴于n,m<=400,改方法肯定不可取的。
解法N:
这种问题,一定要想方设法的避免重复计算问题,可以考虑以空间换时间的方式去实现。
想法1: 积分图的方法://跟图像上的积分图一个概念。
伪代码
1. 计算改n*m矩阵的积分图,时间复杂度为O(n*m);
2. 再穷举所有的正方形子区域(O(n^2))
3. 计算该正方形区域的所有的元素和O(1)
4. 纵上改方法的时间复杂度为O(n*n),鉴于n,m<=400,所以该方法的效率不算太低。
源代码:
#include<iostream>
using namespace std;
int data[400][400];//原始数据
int ig[401][401];//积分图
bool evaluate(int a,int b,int edge)
{
int sum=(ig[a+edge][b+edge]-ig[a+edge][b]-ig[a][b+edge]+ig[a][b]);
if(sum==(edge*edge))
return true;
else
return false;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>data[i][j];
}
//计算积分图
for(int i=0;i<=n;i++)
{
ig[i][0]=0;
}
for(int j=0;j<=m;j++)
{
ig[0][j]=0;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ig[i][j]=ig[i-1][j]+ig[i][j-1]-ig[i-1][j-1]+data[i-1][j-1];
}
}
//计算所有可能的子正方形区域
//子正方形区域内的元素如果都为1,则其积分图为边长的平方.
int max_edge=m>n?n:m;
for(int edge=max_edge;edge>=1;edge--)
{
for(int i=0;i<=n-edge;i++)
for(int j=0;j<=m-edge;j++)
{
if(evaluate(i,j,edge))
{
cout<<edge<<endl;
return 0;
}
}
}
//
cout<<0<<endl;
return 0;
}
可惜当时做的时候,没有想到这个,只是在考完回来的路上才想到的。