1. 打表
1,在程序中一次性计算出所有需要用到的结果,之后的查询直接取这些结果
2,在程序B中分一次或多次计算出所有需要用到的结果,手工把结果写在程序A的数组中,然后再程序A中直接使用这些结果
3,对一些感觉不会做的题目,先用暴力程序计算小范围数据的结果,然后找规律
2. 随机选择算法
从一个无序的数组中求出第K大的数
题目:给定一个由整数组成的集合,集合中的整数各不相同,现在要将它分为两个子集合,使得这两个子集合的并为原集合、交为空集,同时在两个子集合的元素个数n1与n2之差的绝对值|n1-n2|尽可能小的前提下,要求它们各自的元素之和S1与S2之差的绝对值|S1-S2|尽可能大。求|S1-S2|
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 100010;
int A[maxn],n;
//选取随机主元,对区间[left,right]进行划分
int randPartition(int A[],int left,int right){
//生成[left,right]内的随机数p
int p = (round(1.0*rand()/RAND_MAX*(right-left)+left));
swap(A[p],A[left]); // 交换A[p]和A[left]
//以下为原先Partition函数划分的过程,不需要改变任何东西
int temp = A[left];
while(left<right){
while(left<right && A[right]<temp) right--;
A[left]=A[right];
while(left<right && A[left]<=temp) left++;
A[left]=A[right];
}
A[left] = temp;
return left;
}
//随机选择算法,在[left,right]中返回第K大的数
int randSelect(int A[],int left,int right,int K){
if(left==right) return A[left]; //边界
int p = randPartition(A,left,right); //划分后主元的位置为p
int M = p-left+1; //A[p]是A[left,right]中的第M大
if(K == M) return A[p]; //找到第K大的数
if(K < M) return randSelect(A,left,p-1,K); //往主元左侧找第K大
else return randSelect(A,p+1,right,K-M); //往主元右侧找第K-M大
}
int main() {
srand((unsigned)time(NULL)); //初始化随机数种子
//sum 和 sum1记录所有整数之和和与切分后前n/2个元素之和
int sum=0,sum1=0;
scanf("%d",&n); //整数个数
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
sum+=A[i]; //累计所有整数之和
}
randSelect(A,0,n-1,n/2); //寻找第n/2大的数,并进行切分
for(int i=0;i<n/2;i++){
sum1+=A[i]; //累计较小的子集合中元素之和
}
printf("%d\n",(sum-sum1)-sum1); //求两个子集合的元素和之差
return 0;
}