nyist 297 GoroSort

来源:互联网 发布:高一地理难点知乎 编辑:程序博客网 时间:2024/04/30 03:42
http://acm.nyist.net/JudgeOnline/problem.php?pid=297
大意:对于一个数组进行排序。可以按住部分元素,对剩余的元素“洗牌”式操作。求解最少的洗牌的次数。
最开始的天真思路:
一个N个元素的集合进行正确排列的操作数应该是排列数N!  
所以结果应该是各个子集的操作数的和。


#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N=1e3+10;bool vis[N];int a[N];double jie(int x){    double ans=1.0;    for(int i=1;i<=x;i++){        ans=ans*i;    }    return ans;}int main(){    int t,ca=1,n;    cin>>t;    while(t--){        memset(vis,0,sizeof(vis));        scanf("%d",&n);        for(int i=1;i<=n;i++) scanf("%d",&a[i]);        double ans=0.0;        for(int i=1;i<=n;i++){            if(vis[a[i]]==0&&a[i]!=i) {                int dex=i,r=0;                while(!vis[a[dex]]){                    vis[a[dex]]=1;                    r++;                    dex=a[dex];                }                ans=ans+jie(r);            }        }        printf("Case #%d: %.6lf\n",ca++,ans);    }    return 0;}


果断WA
对每一个子集进一步深入分析,操作次数还可以更少:
对于2、1的2元素子集该是2个操作,这没有什么质疑的。那么对于3、1、2的子集呢?


排序完成的操作数的期望应该是 
一开始,一共有3种固定方式,每一种固定方式下,有 成功的概率,共有4种结果。
所以,得到上诉期望。

同样,对于4个元素的集合:

结果就是
发现规律,结果就该是不在本位置上的元素的个数.

#include <iostream>#include <cstdio>#include <cstring>using namespace std;int main(){    int t,ca=1,n;    cin>>t;    while(t--){        scanf("%d",&n);        double ans=0.0;        int t=0;        for(int i=1;i<=n;i++) {            scanf("%d",&t);            if(t!=i) ans++;        }        printf("Case #%d: %.6lf\n",ca++,ans);    }    return 0;}



0 0
原创粉丝点击