目录
1031 输油管道问题 (1)
解题思路 (1)
程序代码 (1)
1032 邮局选址 (4)
解题思路 (4)
程序源代码 (4)
1034 集合划分2 (6)
解题思路: (6)
程序源代码: (6)
1033 集合划分 (8)
解题思路 (8)
程序源代码 (8)
1031 输油管道问题
解题思路
本题目可以分为两个步骤:
1、找出主管道得位置;
2、根据主管道得位置,计算各个油井到主管道得长度之与。
根据题意,设主管道贯穿东西,与y 轴平行。
而各个子油井则分布在主输油管道得上下两侧。
如下图:
由上图,其实只需要确定主管道得y 坐标,而与各个子油井得x 坐标无关!根据猜测,易知:主管道得y 坐标就就是所有子油井y 坐标得中位数。
(可以用平面几何知识证明,略)
求中位数得方法可以用排序后取a[(left+right)/2],当然更推荐用书上得线性时间选择算法解决。
记求得得主管道为,最后要输出得结果只需要计算:,输出即可。
另外要提醒得就是本题多Case。
程序代码
#include<stdio、h>
#include<stdlib、h>
void s &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
//本函数求arr[p:q]得一个划分i,使arr[p:i-1]都小于arr[i],arr[i+1,q]都大于arr[i]
int partition(int *arr,int p,int q)
{
int index = p-1,start = p,base = arr[q];
for(;start<q;start++)
{
if(arr[start]<=base)
{
s[start],arr[++index]);
}
}
s[++index],arr[q]);
return index;
}
//快速排序
void qsort(int *arr,int p ,int q)
{
if(p<=q)
{
int pos = partition(arr,p,q);
qsort(arr,p,pos-1);
qsort(arr,pos+1,q);
}
}
int arr[10001];
int main()
{
int n;
//注意多case 写法
while(scanf("%d",&n)!=EOF)
{
//读取数据
for(int i=0;i<n;i++)
{
//读取y
scanf("%d %d",&arr[i],&arr[i]);
}
//排序
qsort(arr,0,n-1);
//取中位数得下标mid,然后计算距离
long long sum = 0;
int mid = arr[n/2];
for(int i=0;i<n;i++)
{
sum += abs(mid - arr[i]);
}
printf("%I64d\n",sum);
}
return 0;
}
1032 邮局选址
解题思路
本题与上一题非常类似,这次就是要找出在居民点中邮局得最佳位置。
很容易想到,这次不仅要确定y 坐标,还要确定x 坐标。
类似猜想可以知道,邮局最佳位置应该为:
等于所有居民点x坐标得中位数;
等于所有居民点y 坐标得中位数;
分别求中位数得过程与上题类似,不再陈述。
最终得计算结果:要求距离之与,输出。
程序源代码
#include<stdio、h>
#include<stdlib、h>
#include<algorithm>
using namespace std;
int x[10000],y[10000];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
//读取x 与y 坐标
for(int i=0;i<n;i++)
{
scanf("%d %d",&x[i],&y[i]);
}
//调用STL中得排序算法,分别对x 坐标与y 坐标进行排序
sort(x,x+n);
sort(y,y+n);
//取x,y 坐标得中位数并计算距离
int midx = x[n/2];
int midy = y[n/2];
long long res = 0;
for(int i = 0;i < n;i++)
{
res += abs(midx-x[i]);
res += abs(midy-y[i]);
}
// 输出结果
printf("%I64d\n",res);
}
return 0;
}
1034 集合划分2
解题思路:
递推公式如下:
F (n,m) =m*F (n −1,m)+F (n −1,m −1)
F(n,m)表示把n 个元素得集合分为m 个子集,有多少种分法。
证明如下:
n 个元素得集合可以划分为F(n,m)个不同得由m 个非空子集组成得集合。
考虑3 个元素得集合,可划分为
① 1 个子集得集合:{{1,2,3}}
② 2 个子集得集合:{{1,2},{3}},{{1,3},{2}},{{2,3},{1}}
③ 3 个子集得集合:{{1},{2},{3}}
∴F(3,1)=1;F(3,2)=3;F(3,3)=1;
如果要求F(4,2)该怎么办呢?
A、往①里添一个元素{4},得到{{1,2,3},{4}}
B、往②里得任意一个子集添一个4,得到
{{1,2,4},{3}},{{1,2},{3,4}},
{{1,3,4},{2}},{{1,3},{2,4}},
{{2,3,4},{1}},{{2,3},{1,4}}
∴F(4,2)=F(3,1)+2*F(3,2)=1+2*3=7
推广,得F(n,m)=F(n-1,m-1)+m*F(n-1,m)
提醒:由于本题数据范围比较大,需要用64 位长整型即__int64 或者long long。
程序源代码:
#include<stdio、h>
//计算把含有n 个元素得集合分割为m 个子集,有多少种解决方案
long long divide(int n,int m)
{
if(m==1 || m==n)
{
return 1;
}
else
{
return divide(n-1,m-1)+m*divide(n-1,m);
}
}
int main()
{
int n,m;
//多case 输入
while(scanf("%d%d",&n,&m)!=EOF)
{
printf("%I64d\n",divide(n,m));
}
return 0;
}
1033 集合划分
解题思路
假定F(n,m)表示整数n得m划分,则整数n得所有划分就是:。
提醒:
1)由于本题数据范围比较大,需要用64 位长整型即__int64 或者long long。
2)如果n比较大得话,递归算法计算时间会比较长,最好用动态规划算法实现。
程序源代码
#include<stdio、h>
//计算把含有n 个元素得集合分割为m 个子集,有多少种解决方案
long long subset(int n,int m)
{
if(n == m || m == 1)
{
return 1;
}
else
{
return subset(n-1,m-1) + m * subset(n-1,m);
}
}
int main()
{
int n;
while(scanf("%d",&n) != EOF)
{
long long sum = 0;
//计算subset(n,i)之与
for(int i=1;i<=n;i++)
{
sum+=subset(n,i);
}
printf("%I64d\n",sum);
}
return 0;
}。