ZOJ 3777 Problem Arrangement

Posted sahdsg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3777 Problem Arrangement相关的知识,希望对你有一定的参考价值。

https://cn.vjudge.net/problem/ZOJ-3777

题目

某人出题,有N道,觉得题目难度按题目顺序增加很没意思。他发现将编号为$i$的题目放到$j$号位置能增加$P_{ij}$的趣味值,于是他将题目随机打乱,计算趣味值,如果达不到他想要的趣味值M就将题目重新随机打乱,如此循环。求他打乱次数的期望。

输入N (1 <= N <= 12)、M (1 <= M <= 500).和矩阵Pij (0 <= Pij <= 100),输出一个不可约分的分数。如果永远都达不到,输出“No solution”。

Sample Input

2
3 10
2 4 1
3 2 2
4 5 3
2 6
1 3
2 4

 

Sample Output

3/1
No solution

题解

如果知道概率,那么$1/$概率就能得到期望

因此就是

\[\frac{1}{\frac{符合条件的情况}{总情况}}\]

总情况是$N!$,可以直接计算,符合条件的情况可以用DP

N<=12,所以可以用状态压缩dp,设$dp[k][F]$为选了k表示的题目,趣味值为F的种类个数,于是可以得到

\[dp[0][0]=1\]

\[dp[k][F]=\sum{dp[k^x][F-P_?]}\]

其中$P_?$是当前问题在这个位置能加的趣味值

由于要计算大于等于M的种类数,于是改变一下,将大于M的都设为M

\[dp[k|x][F+P_?]+=\sum{dp[k][F]}\]

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#define REP(r,x,y) for(register int r=(x); r<(y); r++)
#define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
#define PERE(r,x,y) for(register int r=(x); r>=(y); r--)
#ifdef sahdsg
#define DBG(...) printf(__VA_ARGS__), fflush(stdout)
#else
#define DBG(...) (void)0
#endif // sahdsg
using namespace std;
typedef long long LL;

#define MAXN 30000007
int n,m;
int p[12][12];
int dp[1<<12][507];
inline int cnt(int i) {
	i = (i&0x55555555)+((i>>1)&0x55555555);
	i = (i&0x33333333)+((i>>2)&0x33333333);
	i = (i&0x0f0f0f0f)+((i>>4)&0x0f0f0f0f);
	i = (i&0x00ff00ff)+((i>>8)&0x00ff00ff);
	i = (i&0x0000ffff)+((i>>16)&0x0000ffff);
	return i;
}
int f[13];
inline int gcd(int a, int b) {
	return b==0? a: gcd(b, a%b);
}
int main() {
	f[0]=1;
	REPE(i,1,12) f[i]=f[i-1]*i;
	int t; scanf("%d", &t);
	while(0<t--) {
		scanf("%d%d", &n, &m);

		REP(i,0,n) {
			REP(j,0,n) {
				scanf("%d", &p[i][j]);
			}
		}

		memset(dp,0,sizeof dp);
		dp[0][0]=1;
		REP(i,0,(1<<n)-1) {
			int ones=cnt(i);
			REPE(j,0,m) if(dp[i][j]) {
				REP(x,0,n) if(!(i&(1<<x))){
					int k=j+p[x][ones]; if(k>m) k=m;
					dp[i|(1<<x)][k]+=dp[i][j];
				}
			}
		}
		int ans=dp[(1<<n)-1][m];
		if(!ans) puts("No solution");
		else {
			int ans2=f[n];
			int g=gcd(ans,ans2);
			printf("%d/%d\n", ans2/g, ans/g);
		}
	}
	return 0;
}

 

以上是关于ZOJ 3777 Problem Arrangement的主要内容,如果未能解决你的问题,请参考以下文章

B - Problem Arrangement ZOJ - 3777

ZOJ-3777 Problem Arrangement(状态压缩DP)

ZOJ-3777-Problem Arrangement(状态DP)

zoj 3777 状压dp || 二分+搜索

ZOJ Problem Set - 1001

ZOJ Problem Set - 1877