求全排列中符合不等式要求的个数

来源:互联网 发布:徐志摩 云中鹤 知乎 编辑:程序博客网 时间:2024/06/02 07:29

度度熊最近对全排列特别感兴趣,对于1到n的一个排列,度度熊发现可以在中间根据大小关系插入合适的大于和小于符号(即 '>' 和 '<' )使其成为一个合法的不等式数列。但是现在度度熊手中只有k个小于符号即('<'')和n-k-1个大于符号(即'>'),度度熊想知道对于1至n任意的排列中有多少个排列可以使用这些符号使其为合法的不等式数列。

思路:

用递归算法找到全排列的每一种情况,判断符合题目要求的不等式数列个数。

#include<iostream>using namespace std;int n,k,value = 0;void prim(int *arr,int begin,int end);int main(){int *array;cin>>n;cin>>k;array = new int[n];for(int i=0;i<n;i++)array[i] = i+1;prim(array,0,n-1);cout<<value<<endl;return 0;   }void myswitch(int *arr,int a,int b){int temp = arr[a];arr[a] = arr[b];arr[b] = temp;}void calculate(int *arr){int tempvalue = 0;for(int j=0;j<n-1;j++)if(arr[j+1]>arr[j])tempvalue++;if(tempvalue == k)value++;}void prim(int *arr,int begin,int end){if(begin == end){calculate(arr);}else{for(int j=begin;j<=end;j++){myswitch(arr,j,begin);prim(arr,begin+1,end);myswitch(arr,j,begin);}}}
虽然以上方法思路简单,但当n很大时,代码运行时间过长,所以寻找另外的方法。

思路2:

 dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) ;
dp[i][j]表示有i个数字及j个小于号所能组成的数量(大于号数量当然是i - j - 1次,后面需要使用)
而加入第i + 1个数字时,分以下四种情况:
1.如果将i+1插入当前序列的开头,即有了1<2,加入后成为3>1<2,会发现等于同时加入了一个大于号!(此时可以无视1与2之间的关系,因为i+1>i)
2.如果将i+1插入当前序列末尾,即1<2变成了 1<2<3,会发现等于同时加入了一个小于号! (此时可以无视1与2之间的关系,因为i+1>i)
3.如果将i+1加入一个小于号之间,即已经有 1<2了,向中间加入3,会发现变成了1<3>2,等于同时加入了一个大于号!
4.如果将i+1加入一个大于号中间,即有了2>1,变成了2<3>1,等于同时加入了一个小于号!
综上所述,dp[i][j]等于以上四种情况之和:
dp[i - 1][j]                                     //将i加在开头等于加入一个大于号,即要求i-1个数时已经有了j个小于号
dp[i - 1][j - 1]                               //将i加在末尾等于加入一个小于号,即要求i-1个数时已经有了j-1个小于号
dp[i - 1][j] * j                                //将i加在任意一个小于号之间,等于加入了一个大于号;即要求i-1个数时已经有了j个小于号,每个小于                                                         号都可以进行这样的一次插入
dp[i - 1][j - 1] * (i- j - 1)              //将i加载任意一个大于号之间,等于加入了一个小于号;即要求i-1个数时有了j-1个小于号,而此时共有
                                                        (i - 1) - (j - 1)- 1个大于号,每个大于号都要进行一次这样的操作
合并同类项即为
 dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) 
#include <iostream>#include <string.h> using namespace std; int dp[1001][1001]; int main() { int n,k,d; while(~scanf("%d%d",&n,&k)) { d=0; memset(dp,0,sizeof(dp)); dp[1][0]=1; for(int i=2; i<=n; i++) for(int j=0; j<i; j++) { if(j==0) dp[i][j]=1; else dp[i][j]=(dp[i-1][j-1]*(i-j)+dp[i-1][j]*(j+1))%2017; } printf("%d\n",dp[n][k]); } return 0; }



0 0
原创粉丝点击