2009 ACM/ICPC 武汉赛区G题解题报告(状态压缩 dp )

题意:

       给你n个数,现在要你调整k个数的位置, 使得具有最少的连续段数;

   比如  n = 5 , k = 1,    27 28 29 27 30

   没调整前 连续段数是5 ,调整为 27 27 28 29 30 后连续段数是4

 

一开始看了一个错误的标程,害我挂了好久!

source code:


#include /!这个题目的dp好难想到啊, 终于看懂了, 唉, 悲哀!
#include
#include
#include
using namespace std;
const int maxn = 101;
const int maxL = 8;
int a[maxn];
char dp[2][1< inline void update(char& x, int v){
    if(x == -1 || x > v) x = v;
}
bool vis[12];
int main(){
    freopen("input.txt", "r", stdin);
    int n, k, cas = 0;
    while(scanf("%d%d", &n, &k)){
        if(n == 0 && k == 0) break;
        memset(vis, false, sizeof(vis));
        printf("Case %d: ", ++cas);
        for(int i = 0; i < n; i ++){
            scanf("%d", &a[i]);
            a[i] -= 25;
            vis[a[i]] = true;
        }
        memset(dp[0], -1, sizeof(dp[0]));
        dp[0][0][0][maxL] = 0;
        // dp[i][j][l1][l2] 表示前i个数在删除了l1个数后的状态是j且其是以l2结尾的;
        //dp[i][j][l1][l2] = -1表示这种状态是不可达的.
        //其中的状态j是表示在前a[0]~a[i]中还剩下数的种类的的状态;
        //比如说i = 5,  a[0] = 1, a[1] = 3, a[2] = 1, a[4] = '-', a[5] = 4;其中a[4]是删除了.
        //则 j = (00011010);    (00011010)表示二进制数.
        // 状态转移方程是dp[i][j][l1][l2] = min(dp[i-1][k][l1][l2], dp[i-1][j][l1+1][l2]);
        //其中 j = k | (1<         for(int i = 0; i < n; i ++){
            memset(dp[(i+1)%2], -1, sizeof(dp[(i+1)%2]));
            for(int j = 0; j < (1<                 for(int l1 = 0; l1 <= k; l1 ++){
                    for(int l2 = 0; l2 <= maxL; l2 ++){
                        int tmp = dp[i%2][j][l1][l2];
                        if(tmp == -1) continue;
//                        printf("dp[%d][%d][%d][%d] = %d/n", i, j, l1, l2, tmp);
                        update(dp[(i+1)%2][j|(1<                                 tmp + (a[i] == l2 ? 0 : 1));
                        update(dp[(i+1)%2][j][l1+1][l2], tmp);
                    }
                }
            }
        }
        int ans = 1000000;
        for(int i = 0; i < (1<             for(int j = 0; j <= k; j ++){
                for(int l1 = 0; l1 <= maxL; l1 ++){
                    int tmp = dp[n%2][i][j][l1];
                    if(tmp == -1) continue;
                    for(int p = 0; p < maxL; p ++){
                        if(vis[p] && (((i>>p)&1)==0)) tmp ++;
                    }
                    ans = min(ans, tmp);
                }
            }
        }
        printf("%d/n/n", ans);
    }
}



一款非常好的锁屏APP软件: 酷划, 不仅好用, 而且还能赚钱, 官网地址: http://www.coohua.com

你可能感兴趣的:(2009 ACM/ICPC 武汉赛区G题解题报告(状态压缩 dp ))