時間: 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;
}
可惜當時做的時候,沒有想到這個,只是在考完回來的路上纔想到的。