zoukankan      html  css  js  c++  java
  • P4329 [COCI2006-2007#1] Bond

    ${color{Cyan}{>>Question}}$

    一道状压的好题

    首先拿到题,想都没想就设$f[l][i][j]$表示第$l$个人在状态$i$(此处的状态为任务是否被完成)下选j任务的最大成功率

    有$$f[l][i][j] = maxleft { f[l-1][i-left { j ight }][k]*p[l][j] ight }$$

    时间复杂度$O(n^3*2^n)$

    空间复杂度$O(n^2*2^n)$

    显然都不行

    但我还是压了一维空间后交了一下,竟然有$75pts$

    代码如下

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 #define ll long long
     6 using namespace std;
     7 
     8 template <typename T> void in(T &x) {
     9     x = 0; T f = 1; char ch = getchar();
    10     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    11     while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
    12     x *= f;
    13 }
    14 
    15 template <typename T> void out(T x) {
    16     if(x < 0) x = -x , putchar('-');
    17     if(x > 9) out(x/10);
    18     putchar(x%10 + 48);
    19 }
    20 //-------------------------------------------------------
    21 
    22 const int N = 20;
    23 
    24 int n;
    25 double f[1<<N][N];
    26 double p[N][N];
    27 
    28 int main() {
    29     //freopen("0_1.in","r",stdin);
    30     int i,j,k,l,a;
    31     in(n);
    32     for(i = 0;i < n; ++i) {
    33         for(j = 0;j < n; ++j) {
    34             in(a); p[i][j] = a/100.0;
    35         }
    36     } 
    37     for(j = 0;j < n; ++j) f[1<<j][j] = p[0][j];//第一层//debug p[0][j] -> p[1][j]
    38     for(l = 1;l < n; ++l) {
    39         for(i = (1<<n)-1; i >= 0; --i) {//逆序 
    40             for(j = 0;j < n; ++j) {
    41                 if(!(i&(1<<j))) continue;
    42                 for(k = 0;k < n; ++k) {
    43                     if(k == j || !(i&(1<<k))) continue;
    44                     f[i][j] = max(f[i][j],f[i^(1<<j)][k]*p[l][j]);
    45                 }
    46             }
    47         }
    48     }
    49     double ans = 0;
    50     for(i = 0;i < n; ++i) ans = max(ans,f[(1<<n)-1][i]);
    51     printf("%lf",ans*100.0);
    52     return 0;
    53 }

    再想想发现第三维根本不需要放进状态中

    令$f[l][i]$表示前$l$个人状态为$i$的最大成功率,只需枚举当前选$j$号任务

    有$$f[l][i] = maxleft { f[l-1][i-left { j ight }]*p[l][j] ight }$$

    时间复杂度$O(n^2*2^n)$

    空间复杂度$O(n*2^n)$

    时间还是不行,但我压了空间交了一遍,有$90pts$

    代码如下

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 #define ll long long
     6 using namespace std; 
     7 
     8 template <typename T> void in(T &x) {
     9     x = 0; T f = 1; char ch = getchar();
    10     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    11     while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
    12     x *= f;
    13 }
    14 
    15 template <typename T> void out(T x) {
    16     if(x < 0) x = -x , putchar('-');
    17     if(x > 9) out(x/10);
    18     putchar(x%10 + 48);
    19 }
    20 //-------------------------------------------------------
    21 
    22 const int N = 20;
    23 
    24 int n;
    25 double f[1<<N];
    26 double p[N][N];
    27 
    28 int main() {
    29     int i,j,l;
    30     in(n);
    31     for(i = 0;i < n; ++i) {
    32         for(j = 0;j < n; ++j) {
    33             in(p[i][j]); p[i][j] /=100.0;
    34         }
    35     } 
    36     for(j = 0;j < n; ++j) f[1<<j] = p[0][j];//第一层
    37     for(l = 1;l < n; ++l) {
    38         for(i = (1<<n)-1; i >= 0; --i) {//逆序 
    39             for(j = 0;j < n; ++j) {
    40                 if(!(i&(1<<j))) continue;
    41                     f[i] = max(f[i],f[i^(1<<j)]*p[l][j]);
    42             }
    43         }
    44     }
    45     printf("%lf",f[(1<<n)-1]*100.0);
    46     return 0;
    47 }

    最后再仔细思考,我们之所以要枚举第$l$个人是因为我们要知道当前以及选了几个人(才有$p$数组)

    但实际上状态$i$中$1$的个数就是当前以及选了几个人

    所以我们令$f[i]$表示状态$i$下的最大成功率

    有$$f[i] = maxleft { f[i-left { j ight }]*p[cnt][j] ight }$$

    $cnt$为$i$中$1$的个数

    时间复杂度$O(n*2^n)$

    空间复杂度$O(2^n)$

    可行

    代码如下

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 #define ll long long
     6 using namespace std; 
     7 
     8 template <typename T> void in(T &x) {
     9     x = 0; T f = 1; char ch = getchar();
    10     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
    11     while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
    12     x *= f;
    13 }
    14 
    15 template <typename T> void out(T x) {
    16     if(x < 0) x = -x , putchar('-');
    17     if(x > 9) out(x/10);
    18     putchar(x%10 + 48);
    19 }
    20 //-------------------------------------------------------
    21 
    22 const int N = 21;
    23 
    24 int n;
    25 double f[1<<N];
    26 double p[N][N];
    27 
    28 int main() {
    29     int i,j;
    30     in(n);
    31     for(i = 0;i < n; ++i) {
    32         for(j = 0;j < n; ++j) {
    33             in(p[i][j]); p[i][j] /=100.0;
    34         }
    35     }
    36     f[0] = 1;
    37     for(i = 1;i < (1<<n); ++i) {
    38         int s = i,cnt = -1;//注意这里是0基准 
    39         /*while(s) {
    40             if(s&1) ++cnt;
    41             s >>= 1; 
    42         }*/
    43         for(;s;s >>= 1) if(s&1) ++cnt;//统计1的个数
    44         for(j = 0;j < n; ++j) {
    45             if(i&(1<<j)) f[i] = max(f[i],f[i^(1<<j)]*p[cnt][j]);
    46         }
    47     }
    48     printf("%lf",f[(1<<n)-1]*100.0);
    49     return 0;
    50 }

    但这题还可以用二分图带权匹配或费用流$A$了

    好吧我也不会$QwQ$

  • 相关阅读:
    C语言 sprintf 函数 C语言零基础入门教程
    C语言 printf 函数 C语言零基础入门教程
    C语言 文件读写 fgets 函数 C语言零基础入门教程
    C语言 文件读写 fputs 函数 C语言零基础入门教程
    C语言 fprintf 函数 C语言零基础入门教程
    C语言 文件读写 fgetc 函数 C语言零基础入门教程
    C语言 文件读写 fputc 函数 C语言零基础入门教程
    C语言 strlen 函数 C语言零基础入门教程
    Brad Abrams关于Naming Conventions的演讲中涉及到的生词集解
    适配器模式
  • 原文地址:https://www.cnblogs.com/mzg1805/p/11359475.html
Copyright © 2011-2022 走看看