递归与分治策略——集合划分问题,众数问题

集合划分问题

n个元素的集合{1,2,.,n }可以划分为若干个非空子集。例如,当n=4 时,集合{1,2,3,4}可以划分为15个不同的非空子集如下:
{1}
{2}{3}{4}} {{12}{3}{4}}

{{1
3}{2}{4}} {{14}{2}{3}}

{{2
3}{1}{4}} {{24}{1}{3}}

{{3
4}{1}{2}} {{12}{34}}

{{1
3}{24}} {{14}{23}}

{{1
23}{4}} {{124}{3}}

{{1
34}{2}} {{234}{1}}

{{1
234}}

编程任务:
给定正整数n m,计算出n 个元素的集合{1,2,., n }可以划分为多少个不同的由m

非空子集组成的集合。

 

算法思路:

n个元素的集合可以划分为F(n,m)个不同的由m个非空子集组成的集合。
考虑3个元素的集合,可划分为

① 1
个子集的集合:{{12
3}}
② 2
个子集的集合:{{12}{3}}{{13}{2}}{{23}
{1}}
③ 3
个子集的集合:{{1}{2}
{3}}
F(3,1)=1;F(3,2)=3;F(3,3)=1;
如果要求F(4,2)该怎么办呢?

A.
里添一个元素{4},得到{{123}
{4}}
B.
里的任意一个子集添一个4,得到

{{1
24}{3}}{{12}{34}}

{{1
34}{2}}{{13}{24}}

{{2
34}{1}}{{23}{1
4}}

F(4,2)=F(3,1)+2*F(3,2)1+2*37

推广,得F(n,m)=F(n-1,m-1)+m*F(n-1,m)

public class SetPartition1 { public int F(int n,int m){ if(n<=2) return 1; if(m==1||n==m) return 1; else return F(n-1,m-1)+m*F(n-1,m); } public static void main(String[] args) throws IOException{ SetPartition1 sp = new SetPartition1(); int a; int s=0; String input; BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); input = stdin.readLine(); a = Integer.parseInt(input); for(int i=1;i<=a;i++){ int t = sp.F(a, i); s=s+t; } System.out.println(s); } }

众数问题

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为众数。例如,S={122235}。多重集S的众数是2,其重数为3

数据输入

输入包括多组数据,请处理到EOF结束。每组数据,以一个n(1<=n<=100,000)开始,接下n行,每行有一个数字(-231~231)

数据输出

对于每组输入数据,输出一行一个数字,表示众数。如果存在多个解,只需输出值最小的众数即可。

 

算法思路:首先用快速排序算法排序数组,找到当前数组的中位数及其位置,然后把在数组中与中位数相同的数字向它靠拢,就可以统计中位数的个数。现在数组已经被中间这些相等的数字分开了。那么递归条件就有了。如果中位数的个数比它左边这段短,那么说明左边有可能找到更多的,所以递归继续。反之,如果左边这段数的长度比较短,那么就没必要继续递归。对右边那段数据使用同样的策略。

 

 

 class ZS{ int element; //元素 int sum; //重数 } //记录中位数的起始下标 class Node{ int low; int high; } public class CountMode { public ZS x = new ZS(); void sort(int a[],int s,int t){ //对数组a进行快速排序 int i=s,j=t; int temp; if(s<t){ temp = a[s]; while(i!=j){ while(j>i&&a[j]>temp) j–; if(i<j){ a[i]=a[j]; i++; } while(i<j&&a[i]<temp) i++; if(i<j){ a[j]=a[i]; j–; } } a[i]=temp; sort(a,s,i-1); sort(a,i+1,t); } } //求中位数 int madian(int a[],int l,int r){ int x=r-l+1; return a[x/2]; } //返回中位数的起始点 Node spalit(int a[],int med,int l,int r){ Node m = new Node(); m.low=l; m.high=r; for(int i=0;i<=r;i++){ if(med==a[i]){ m.low=i; break; } } for(int j=r;j>=0;j–){ if(med==a[j]){ m.high=j; break; } } return m; } //求众数 void mode(int a[],int l,int r){ if(l>=r) return; else{ Node n; int temp=0; int med; med=this.madian(a, l, r); n = this.spalit(a, med, l, r); temp=n.high-n.low+1; if(x.sum<temp){ x.element = med; x.sum=temp; } if(n.low-1>temp){ if(x.sum<temp){ x.element = med; x.sum=temp; } mode(a,l,n.low-1); } if(r-n.high>temp){ if(x.sum<temp){ x.element = med; x.sum=temp; } mode(a,n.high+1,r); } } }

 

 

    原文作者:递归与分治算法
    原文地址: https://blog.csdn.net/christophe2008/article/details/6338726
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞