设为首页 加入收藏

TOP

一道DP练习题详解(三)
2013-12-12 14:36:53 来源: 作者: 【 】 浏览:485
Tags:一道 习题 详解

 

    POJ 2096 求期望--8.16

    求期望一道比较简单的题。用dp[i][j]表示i个系统,j个bug是的期望。

    那么dp[i][j] 可以由下面几个状态得到

    dp[i + 1][j] *j * 1.0 / n * (s - i) * 1.0 / s ,表示下个bug是相同的bug,但是是属于不同系统的,则概率就是(s - i) / s * j / n ;

    dp[i][j + 1] * (n - j) * 1.0 / n * i * 1.0 / s) ,表示下个bug是不相同的bug,但是属于同一系统,概率为i / s * (n - j) / n ;

    dp[i + 1][j + 1] * (n - j) * 1.0 / n * (s - i) * 1.0 / s,表示下个bug不相同,也不属于同一系统,概率为(s - i) / s * (n - j) / n ;

    dp[i][j] * i / s * j / n ,表示下个bug出现过,也属于同一系统,概率为i / s * j / n ;

    由dp[s][n] = 0 ,推出dp[0][0]即可。

    #define N 1005

    double dp[N][N] ;//dp[i][j] . i means s systems , j means n bugs .

    int main() {

    int n , s ;

    while(cin 》 n 》 s ) {

    dp[s][n] = 0 ;

    for (int i = s ; i >= 0 ; i -- ) {

    for (int j = n ; j >= 0 ; j -- ) {

    if(i == s && j == n)continue ;

    dp[i][j] = //dp[i][j] * (double)(i * 1.0 / s * j * 1.0 / n) +

    ( dp[i + 1][j] * (double)(j * 1.0 / n * (s - i) * 1.0 / s) +

    dp[i + 1][j + 1] * (double)((n - j) * 1.0 / n * (s - i) * 1.0 / s) +

    dp[i][j + 1] * (double)((n - j) * 1.0 / n * i * 1.0 / s) + 1 ) / (1 - i * 1.0 / s * j * 1.0 / n );

    //                cout 《 dp[i][j] 《 endl;

    }

    }

    printf("%.4f\n",dp[0][0]) ;

    }

    return 0 ;

    }

    POJ 3254 状压DP --8.16

    类似炮兵阵地,不过更简单,这道题的攻击范围就上下左右四个格子,所以只需开二维的dp[][]即可。

    dp[i][j]表示状态i ,当前在j行的可行总和。

    这里因为求的不是最大放置的个数,所以转移方程有点不同,但是我觉得比那个更简单,dp[i][j] = dp[i][j] + dp[k][j - 1] .

    int dp[1111][13] ;

    int Map[20][20] ;

    int Cmap[13] ;

    int n , m ;

    int fk[1111] ;

    int nfk[1111] ;

    int nk ;

    ll c[1111] ;

    int ok(int x) {

    if(x & (x 《 1)) return 0 ;

    if(x & (x 》 1)) return 0 ;

    return 1 ;

    }

    void get_statu() {

    for (int i = 0 ; i < 1 《 m ; i ++ ) {

    if(ok(i)) {

    int t = i ;

    int nn = 0 ;

    while(t) {

    nn += t % 2 ;

    t /= 2 ;

    }

    fk[nk] = i ;

    nfk[nk ++] = nn ;

    }

    }

    }

    void init() {

    mem(Cmap ,0) ;

    mem(fk ,0) ;

    mem(nfk ,0) ;

    nk = 0 ;

    mem(c ,0) ;

    }

    int main() {

    while(cin 》 n 》 m) {

    init() ;

    get_statu() ;

    for (int i = 1 ; i <= n ; i ++ ) {

    for (int j = 1 ; j <= m ; j ++ ) {

    cin 》 Map[i][j] ;

    if(!Map[i][j])Cmap[i] += 1 《 j - 1 ;

    }

    }

    for (int i = 0 ; i < nk ; i ++ ) {

    if((fk[i] & Cmap ))continue ;

    dp[i] = 1 ;

    }

    for (int i = 2 ; i <= n ; i ++ ) { //当前行

    for (int j = 0 ; j < nk ; j ++ ) { //上一状态

    if(fk[j] & Cmap[i - 1])continue ;

    for (int k = 0 ; k < nk ; k ++ ) { //当前状态

    if(fk[k] & Cmap[i])continue ;

    if(fk[j] & fk[k])continue ;

    dp[k][i] = (dp[k][i] + dp[j][i - 1]) % 100000000 ;

    }

    }

    }

    ll ans = 0 ;

    for (int i = 0 ; i < nk ; i ++ ){

    ans = (ans + dp[i][n]) % 100000000 ;

    }

    cout 《 ans 《 endl ;

    }

    return 0 ;

    }

    HDU 4540 -8.20

    水题,二维DP.

    dp[i][j]表示i时间,打j这个老鼠。

    int n , m ;

    int M[22][22] ;

    int dp[22][11] ;

    int main() {

    while(cin 》 n 》 m) {

    mem(dp ,0) ;

    for (int i = 1 ; i <= n ; i ++ ) {

    for (int j = 1 ; j <= m ; j ++ ) {

    cin 》 M[i][j] ;

    }

    }

    for (int i = 0 ; i <= n ; i ++ ) {

    for (int j = 0 ; j <= m ; j ++ ) {

    dp[i][j] = inf ;

    }

    }

    for (int i = 1 ; i <= m ; i ++ ) {

    dp [i] = 0 ;

    }

    for (int i = 2 ; i <= n ; i ++ ) {

    for (int j = 1 ; j <= m ; j ++ ) {

    for (int k = 1 ; k <= m ; k ++ ) {

    dp[i][k] = min(dp[i][k] , dp[i - 1][j] + abs(M[i - 1][j] - M[i][k])) ;

    }

    }

    }

    int ans = inf ;

    for (int i = 1 ; i <= m ; i ++ ) {

    ans = min(ans , dp[n][i]) ;

    }

    cout 《 ans 《 endl;

    }

    return 0 ;

    }

    POJ 1159 LCS--09.14

    最长公共子序列。

    这道题是求加多少个字符使得他成为回文。

    我们就可以求他和逆串的最长公共子序列,然后用长度减去他。就是需要加的最少的数量。

    贴个LCS的模版。

    short dp [5005] ;

    string x , y ;

    int main() {

    int n ;

    while(cin 》 n){

    cin 》 x ;

    y = x ;

    reverse(y.begin() , y.end()) ;

    mem(dp ,0) ;

    for (int i = 1 ; i <= n ; i ++ ){

    for (int j = 1 ; j <= n ; j ++ ){

    if(x[i - 1] == y[j - 1]){

    dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + 1 ;

    }

    else {

    dp[i % 2][j] = max(dp[i % 2][j] , max(dp[(i - 1) % 2][j] , dp[i % 2][j - 1])) ;

    }

    }

    }

    cout 《 n - dp[n % 2][n] 《 endl;

    }

    return 0 ;

    }

        

首页 上一页 1 2 3 4 5 6 7 下一页 尾页 3/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇根据括号匹配求区间DP 下一篇计算气球半径让其不相交

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·Libevent C++ 高并发 (2025-12-26 00:49:30)
·C++ dll 设计接口时 (2025-12-26 00:49:28)
·透彻理解 C 语言指针 (2025-12-26 00:22:52)
·C语言指针详解 (经典 (2025-12-26 00:22:49)
·C 指针 | 菜鸟教程 (2025-12-26 00:22:46)