hdu_2048 错排问题
错排问题本质上就是一个动态规划问题,其状态转移方程为:
记d[n]为n个人错排情况的总数。
那么策略可以描述为:分析第n个人错排的可能情况:
1)前n-1个人满足错排的情况,那么第n个人加入后还要错排意味着第n个人与前n-1个人里的任意一个交换字条(共有n-1种交换法)
2)若前n-1个人并不满足错排,但加入第n个人后满足错排。这必然意味着第n个人加入后与前n-1中的某个人交换字条后才满足n个人错排。而又因为原本前n-1人不满足错排,那么前n-1个人中至少有一个人手上的字条是匹配的,那么第n个人就只能与匹配者交换字条。此时可以证明前n-1人中字条匹配者人数不能大于1,可以反证(如果有两人字条匹配,那么在第n个人交换后必然还有一个人字条匹配,不满足)
tip:
printf()输出百分号的时候,有的oj上必须写成%%,有的可以写成%。严格点的话,还是采用第一种写法稳妥。
ac代码如下:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; //错排思想 long long d[30]; long long f(int n){ if(d[n]!=-1){ return d[n]; } else{ d[n]=(n-1)*(f(n-1)+f(n-2)); return d[n]; } } int main(void){ memset(d,-1,sizeof(d)); d[1]=0;d[2]=1; f(20); int c; scanf("%d",&c); while(c--){ int n; scanf("%d",&n); long long cnt1=d[n]; long long cnt2=1; for(int i=1;i<=n;i++){ cnt2*=i ; } double ans=double(cnt1)/double(cnt2); printf("%.2lf%%\n",ans*100); //printf("%.2lf%\n",ans*100); //这样写就是wronganser } return 0; }