P4329 [COCI2006-2007#1] Bond

Problem

一道很有意思的状压DP

如果硬做 这题的空间是 \(O(2^{40})\) 时间是 \(O(2^{40} * n^2)\)

有n个人去执行n个任务,每个人执行每个任务有不同的成功率,每个人只能执行一个任务,求所有任务都执行的总的成功率。

很显然这题 求的是最大的概率 每个人都不一样…肯定是状压(费用流

考虑怎么压一维做…因为这个是一一对应的 会少掉很多状态
比如

1->2
2->3
3->1

2->3
1->2
3->1

是一样的 这样就可以按来状压了…

所以 \(dp_i\) 表示 做过任务的人
然后你可以根据 二进制位为1的个数推断出现在在选第几个物品…然后枚举当前未选过物品的人进行转移

#include<bits/stdc++.h>
using namespace std ;
#define int long long
#define fi first
#define se second
#define pb push_back
inline int read() {
	register int x = 0 , f = 1 ;
	register char c = getchar() ;
	for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
	for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
	return x * f ;
}
template < typename T > inline bool cmax(T & x , T y) {
	return x < y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cmin(T & x , T y) {
	return x > y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cabs(T & x) {
	return x > 0 ? 1 : (x = - x) , 0 ;
}
inline int QP(int x , int y , int Mod) {
	int ans = 1 ;
	for( ; y ; y >>= 1 , x = (x * x) % Mod)
		if(y & 1) ans = (ans * x) % Mod ;
	return ans ;
}
int n ;
const int N = 21 ;
double dp[1 << N] ;
double c[N][N] ;
signed main() {
	n = read() ;
	for(register int i = 1 ; i <= n ; i ++)
		for(register int j = 1 ; j <= n ; j ++) c[i][j] = read() ;
	for(register int i = 1 ; i <= n ; i ++)
		for(register int j = 1 ; j <= n ; j ++) c[i][j] /= 100 ;
	int s = (1 << n) - 1 ;
	dp[0] = 1.00 ;
	for(register int i = 0 ; i <= s ; i ++) {
		int cnt = 1 ;
		int t = i ; while(t) t -= (t & -t) , cnt ++ ;
		for(register int j = 1 ; j <= n ; j ++)
			if(! (i & (1 << j - 1))) cmax(dp[i | (1 << j - 1)] , 1.0 * dp[i] * c[j][cnt]) ;
	}
	printf("%.9f" , dp[s] * 100) ;
	return 0 ;
}

posted @ 2019-10-07 13:05  _Isaunoya  阅读(183)  评论(0编辑  收藏  举报