题意:N道题目,排序,每道题在不同的位置得到的值不同。
求随机排序后得到值大于等于m的期望次数。
因为是随机排序,所以期望就是 总数/可行数
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
#define ll long long
int n,m,t;
int a[14][14];
int dp[1<<13][501];
vector<int>number[14];
int gcd(int x, int y)
{
return y?gcd(y,x%y):x;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) cin>>a[i][j];
memset(dp,0,sizeof(dp));
for(int i=0;i<=n;i++)
number[i].clear();
for(int i=0;i<(1<<n);i++)//分类出 1 个数不同的数
{
int x=i,num=0;
while(x)
{
if(x&1) num++;
x=x>>1;
}
number[num].push_back(i);
}
for(int i=0;i<n;i++)//第一行的状态
{
int kk=a[0][i];//注意
if(kk>m) kk=m;
dp[1<<i][kk]=1;
}
for(int i=1;i<n;i++)//行
{
for(int k=0;k<number[i].size();k++)//枚举上一行状态
{
int x=number[i][k];
for(int j=0;j<n;j++)//枚举该行的位置
{
if((x&(1<<j))==0)//上一行中不含j位置
{
int c=(1<<j);
for(int p=0;p<=m;p++)
{
int point=p+a[i][j];
if(point>m) point=m;
dp[x|c][point]+=dp[x][p];
}
}
}
}
}
int sum=1;
for(int i=1;i<=n;i++)
sum*=i;
int gcdnum=gcd(sum,dp[(1<<n)-1][m]);
if(dp[(1<<n)-1][m]==0)
printf("No solution\n");
else printf("%d/%d\n",sum/gcdnum,dp[(1<<n)-1][m]/gcdnum);
}
return 0;
}
/*
*/