Queue

Queue

       可以說是排列組合,可以說是動態規劃,還可以說是遞推。其實,可以直接遞推打表,後面直接輸出就還了,相當於也是以空間換時間。

       有n個人(高度不一)排成一列,從隊列的最前看只能看到p個人,從隊列的最後面看只能看到r個人(有的人可能被遮住了)。問排成這種隊列的排法有多少種。

       對於有n個人的隊列,那是n-1個人的隊列裏面加了一個人(假設最身高最矮)。這個人可能加在中間,那麼他有n-2個位置可以站,最前最後兩個位置不能站,就有【n-1個人,前看p個人,後看r個人】*(n-2)中排法;要是這個人排在隊列的最前面,則有【n-1個人,前看p-1個人(加1後就是p個人),後看r個人】;同理,要是他站在隊伍最前面,則有(n-1個人,前看p個人,後看r-1個人)重排法。

       遞推方程:dp[i][j][k]=dp[i-1][j][k]*(i-2)+dp[i-1][j][k-1]+dp[i-1][j-1][k];

        dp[i][j][k]表示共有i個人排成一列,從前看能看到j個人,從後看能看到k個人的排法有dp[i][j][k]種。

       (1)若i==j+k-1並且j,k有一個等於1,dp[i][j[][k]=1,這時候是整個隊伍的人從前到後按身高嚴格升序或嚴格降序排列的。或是最高的在中間,兩邊式嚴格像中間遞增的。這些情況,都只有一種排法。

        (2)否則,若i=1並且j=1,則dp[i][j][k]=0,因爲最高那個人不可能即在隊頭,又在隊尾。注,n=1的這種情況在上面就已經處理了,不會走到這一步

        (3)否則,直接用公式算就好了。

      在輸出的時候還要注意,要是j+k-1>i(題目沒說輸入的p,r之和不大於n+1),那麼dp[i][j][k]=0。這種隊列不可能排的出來,至於爲什麼,讀者朋友自己思考,實在想不通的,請留言。


include<cstdio> #include<iostream> #include<cstring> using namespace std; int main() {     int n,p,r;     long long dp[14][14][14];     int i,j,k;     memset(dp,0,sizeof(dp));     dp[0][0][0]=1;     for(i=1; i<14; i++)     {         for(j=1; j<=i; j++)         {             for(k=1; k<=i-j+1; k++)             {                 if((i==j+k-1)&&(j==1||k==1))   //遞增(或遞減)有序排列                     dp[i][j][k]=1;                 else if(j==1&&k==1)dp[i][j][k]=0;   //不可能排列                 else                     dp[i][j][k]=dp[i-1][j][k]*(i-2)+dp[i-1][j][k-1]+dp[i-1][j-1][k];   //隨機有可能排列             }         }     }     int t;     cin>>t;     while(t--)     {         cin>>n>>p>>r;         if(p+r>n+1)cout<<"0"<<endl;  //注意細節啊,鄙人就在這裏WA了一次         else cout<<dp[n][p][r]<<endl;     }     return 0; }   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章