问题描述
给定N个整数A[i]以及一个正整数C,问其中有多少对i,j满足A[i]-A[j]=C。
输入描述
第1行输入两个空格隔开的整数N和C,第2~N+1行每行包含一个整数A[i].
输出一个数表示答案
主要算法思想
此设计中主要采用了分治算法的一些思想
分治算法的主要思想
当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。
使用分治算法的基本步骤
step1 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
step2 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
step3 合并:将各个子问题的解合并为原问题的解。
分治算法的应用条件
1.问题的规模缩小到一定程度就可以容易地解决。
2.问题具有最优子结构性质(当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质)
3.分解出的子问题的解可以合并为该问题的解。
4.问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
在这个问题中分治算法的具体应用
首先采用二分查找数量。先对数组a递增排序,用j扫描数组a,对于元素a[j],在a[j+1…n-1]中采用二分法求元素a[j]+c出现的次数count(不存在时count=0),累计所有的count得到ans即为所求。其中在有序序列中查找a[j]+c元素出现次数的二分发就是分治思路。
详细设计
search函数模块(分治算法模块)
int search(int low,int high,int x)
{
while(low<=high)
{
int mid = (low+high)/2;
if(a[mid]==x)
{
int count=1,i;
i=mid-1;
while(i>=low&&a[i]==x)
{
count++;
i--;
}
i=mid+1;
while(i<=high&&a[i]==x)
{
count++;
i++;
}
return count;
}
else if(x>a[mid])
low=mid+1;
else
high=mid-1;
}
return 0;
}
主函数模块
int main(){
scanf("%d%d",&n,&c);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int ans = 0;
for(int j=0;j<n-1;j++)
ans+=search(j+1,n-1,a[j]+c);
printf("A[i]-A[j]=c出现的次数为%d\n",ans);
return 0;}
流程图
主函数模块流程图
search函数模块流程图(算法模块)
详细代码
#include<stdio.h>
#include<algorithm>
using namespace std;
#define MAXN 200000
int a[MAXN];
int n,c;
int search(int low,int high,int x)
{
while(low<=high)
{
int mid = (low+high)/2;
if(a[mid]==x)
{
int count=1,i;
i=mid-1;
while(i>=low&&a[i]==x)
{
count++;
i--;
}
i=mid+1;
while(i<=high&&a[i]==x)
{
count++;
i++;
}
return count;
}
else if(x>a[mid])
low=mid+1;
else
high=mid-1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&c);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
int ans = 0;
for(int j=0;j<n-1;j++)
ans+=search(j+1,n-1,a[j]+c);
printf("A[i]-A[j]=c出现的次数为%d\n",ans);
return 0;
}