您的位置:首页 > 其它

算法设计与分析—分治

2020-04-07 12:23 971 查看

1.Aggressive cows (二分)
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

  • Line 1: Two space-separated integers: N and C

  • Lines 2…N+1: Line i+1 contains an integer stall location, xi

Output

  • Line 1: One integer: the largest minimum distance
    Sample Input
    5 3
    1
    2
    8
    4
    9
    Sample Output
    3

不得不说英文题真的非常……(此处省略好多字),这个题也是不明白什么意思吧。现在再看一下。

母牛很好斗,

2.Ignatius and the Princess II (全排列)
Now our hero finds the door to the BEelzebub feng5166. He opens the door and finds feng5166 is about to kill our pretty Princess. But now the BEelzebub has to beat our hero first. feng5166 says, “I have three question for you, if you can work them out, I will release the Princess, or you will be my dinner, too.” Ignatius says confidently, “OK, at last, I will save the Princess.”

“Now I will show you the first problem.” feng5166 says, “Given a sequence of number 1 to N, we define that 1,2,3…N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it’s easy to see the second smallest sequence is 1,2,3…N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It’s easy, isn’t is? Hahahahaha…”
Can you help Ignatius to solve this problem?

Input
The input contains several test cases. Each test case consists of two numbers, N and M(1<=N<=1000, 1<=M<=10000). You may assume that there is always a sequence satisfied the BEelzebub’s demand. The input is terminated by the end of file.

Output
For each test case, you only have to output the sequence satisfied the BEelzebub’s demand. When output a sequence, you should print a space between two numbers, but do not output any spaces after the last number.

Sample Input
6 4
11 8

Sample Output
1 2 3 5 6 4
1 2 3 4 5 6 7 9 8 11 10

不翻译还真不知道是勇士闯入了魔兽大门营救公主(ノ ̄▽ ̄)
这魔兽出题了,问勇士能不能求出1~n的第m个全排列
此处深感到之前学会的next_permutation()函数的好处

下面是AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int a[1001];
int main(){
int n,m; //一共n个数,第m个序列
while(scanf("%d %d",&n,&m)!=EOF){
memset(a,0,sizeof(a));
for(int i=0;i<n;i++)
a[i]=i+1;
while(--m)
next_permutation(a,a+n);
for(int i=0;i<n-1;i++)
printf("%d ",a[i]);
printf("%d",a[n-1]);
printf("\n");
}
return 0;
}

这个题注意两点:
1.一开始是对数组下标1-n赋值,怎么都没对,之后改成对0-n-1赋值就可以了,初步觉得是函数对a-a+n范围全排列牵扯数组下标0有些问题。
2.注意不要pe,做什么题都要看清格式,也是英文题有干扰一下吧,后面没有空格就不要写啦

3.Ignatius and the Princess III (整数划分)
先补充一点小知识,看到下面的知识写的很好:

分治法的基本思想:将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解这些问题,然后将各个子问题的解合并成原问题的解。
分治法所能解决的问题一般具有以下几个特征:

该问题的规模缩小到一定的程度就可以容易地解决;因为问题的计算复杂性一般是随着问题规模的增加而增加,因此大部分问题满足这个特征。

该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质这条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用

利用该问题分解出的子问题的解可以合并为该问题的解;能否利用分治法完全取决于问题是否具有这条特征,如果具备了前两条特征,而不具备第三条特征,则可以考虑贪心算法或动态规划。

该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。这条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好(例如记忆化搜索是分治转化为动归的一个经典)。

“Well, it seems the first problem is too easy. I will let you know how foolish you are later.” feng5166 says.

“The second problem is, given an positive integer N, we define an equation like this:
N=a[1]+a[2]+a[3]+…+a[m];
a[i]>0,1<=m<=N;
My question is how many different equations you can find for a given N.
For example, assume N is 4, we can find:
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
so the result is 5 when N is 4. Note that “4 = 3 + 1” and “4 = 1 + 3” is the same in this problem. Now, you do it!”

Input
The input contains several test cases. Each test case contains a positive integer N(1<=N<=120) which is mentioned above. The input is terminated by the end of file.

Output
For each test case, you have to output a line contains an integer P which indicate the different equations you have found.

Sample Input
4
10
20

Sample Output
5
42
627

故事还是那个故事,第一个问题人家答出来了还不能接公主走,还要答第二个,魔兽就是魔兽啊!
这次问题高级太多了,整数划分问题。输入第一行是整数,输出是这个整数有多少划分。
上来啥也不说一通递归 如下 ↓

#include <iostream>
using namespace std;
int spilt(int n,int m){
if(n==1||m==1)
return 1;
else if(n<m)
return spilt(n,n);
else if(n==m)
return spilt(n,m-1)+1;
else
return spilt(n,m-1)+spilt(n-m,m);
}
int main(){
int n;
while(cin>>n){
cout<<spilt(n,n)<<endl;
}
return 0;
}

所谓分治,分而治之。这个函数有两个变量,n是我们所求,m是小于n的数。n是我们所求,m代表最大加数不大于m的划分数。什么意思呢?举例来说,n是4,即求4的整数划分时,m可在递归过程中依次取4,3,2,1。当然了,如果m大于n,递归时会将m变为n。下面依次看递归条件:
①n等于1时划分数自然只有1,而m=1是递归的边界条件,即已经到了不大于1的加数的划分,自然也只有一个;
②n<m时将m变为n;
③n等于m时,自然只有一个是本身,所以先加上1,然后m-1遍历;
④n>m>1时,要加上m的整数划分,和m-1的整数划分。
很好,变得很简洁。但!
超时了!哎呀怎么超时了呢……递归时间复杂度太高了
所以搜索了一下用动态规划……并且,用cin cout还re了,要用scanf printf。

#include<iostream>
using namespace std;
int dp[121][121];
int solve(int n){
for(int i=1;i<=n;i++)
dp[0][i]=1;
for (int i=1;i<=n;i++){
dp[i][0]=0;
for(int j=1;j<=n;j++){
if(i<j)
dp[i][j]=dp[i][i];
else
dp[i][j]=(dp[i-j][j]+dp[i][j-1]);
}
}
return dp[n][n];
}
int main() {
int n,ans;
while(cin>>n){
cout<<solve(n)<<endl;
}
return 0;
}

4.第k大数
给出两个数字的集合,A,B分别从中挑选一个中把两个数相乘,这样可以得到另外一个集合C。请问一下集合C中第k大的数是多少?

Input
多组测试数据
每组测试中,第一行输入两个整数m,n,k(0 < n,m,k<50)k的值不大于C中集合个数
第二行有m个数代表集合A中的元素
第三行有n个数代表集合B中的元素

Output
对于每组测试数据输出一行,代表C中第k大的数

Sample Input
2 2 3
1 2
3 4

Sample Output
4

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2600;
ll a[N];
ll b[N];
ll c[N];
int main(){
int m,n,k;
while(cin>>m>>n>>k){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
int t=0;
for(int i=0;i<m;i++)
cin>>a[i];
for(int j=0;j<n;j++)
cin>>b[j];
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
c[t++]=a[i]*b[j];
sort(c,c+(m*n));
int length=m*n;
for(int i=0;i<length;i++){
if(c[i]==c[i+1]){
for(int j=i;j<length;j++)
c[j]=c[j+1];
length--;
i--;
}
}
sort(c,c+length);
cout<<c[length-k]<<endl;
}
return 0;
}

这题没有多想,也没有用分治,直接把a、b两个数组相乘的值存入c数组中,排序输出第k大数即可,但要记得一个关键问题是去重,两个数组中相乘可能得到相同的数,把这些重复数去掉才可以重新排序得到第k大数。

  • 点赞
  • 收藏
  • 分享
  • 文章举报
是IMI呀 发布了38 篇原创文章 · 获赞 0 · 访问量 721 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: