• 【Uva 1289】Stacking Plates


    Link:

    Description

    有n(1≤n≤50)堆盘子,第i堆盘子有hi个盘子(1≤hi≤50),从上到下直径不减。所有盘 子的直径均不超过10000。有如下两种操作。
    split:把一堆盘子从某个位置处分成上下两堆。
    join:把一堆盘子a放到另一堆盘子b的顶端,要求是a底部盘子的直径不超过b顶端盘子 的直径。
    你的任务是用最少的操作把所有盘子叠成一堆

    Solution

    假设我们进行了x次split操作;

    我们总共需要的操作次数为x+x+n-1
    因为进行一次split操作,连通块的个数就会递增1;
    进行x次的话,就有x+n块;
    然后把这x+n块合并成一块的话;
    需要x+n-1次join操作;
    再加上x次split操作;
    总共就是2*x+n-1次操作;
    然后我们考虑最后所有的方块都叠成了一块的情形
    假设,我们一开始把n堆的每一堆都染成同一种颜色;
    则最后只剩一堆方块的时候,肯定是不同颜色相间的;
    设最后只剩一堆方块的时候,上下相邻的单个方块之间,颜色不同的对数为cnt;
    答案就为2*cnt-n+1
    为什么不是上面分析的2*x+n-1次操作?
    因为这里的cnt并不是分离的次数;
    想一想,如果没有进行分离操作,直接全部叠在一个上面,肯定也有n-1个对是不相等的颜色;
    则我们求出的cnt如果想变成分离的次数应该减去2*(n-1)
    即2*(cnt-2*(n-1))+n-1 = 2*cnt-n+1
    这样,就能根据最后答案的那一叠方块知晓答案了;
    这可以给我们的DP提供思路;
    我们就对最后的答案的那一堆进行DP;
    在DP之前;
    我们先将所有的盘离散化一下;
    因为盘的直径最大达到了10000;
    直接枚举盘的直径可能会跨了很多;
    而盘子的数目最多为2500
    然后,同一堆里的盘子,如果它的直径是一样的,那就把它们都当成一个盘子就好了;
    之后;
    考虑最后的答案构成的一堆盘子;
    肯定是从上到下,盘子的直径不下降的;
    则我们,从上到下,依次枚举每个盘子,它要放在哪一堆上面;
    设f[i][j]表示,直径小于等于i(已经离散化过)的盘子,把它们都放到第j堆盘子上,最小的相邻不同颜色对数;
    对于f[i][]这个状态肯定是移动到已经有i这个盘子的堆上比较划算;
    设为j
    则转移的时候;
    只要找有i-1这个盘子的堆k;
    然后用f[i-1][k]这个状态转移到f[i][j]
    算一下会增加多少个相邻不同颜色就好;
    转移的过程实际上就是其他i盘子移动到那个j上,以及k那一堆i-1盘子之上的整个移动到i上面来
    (注意如果k那一堆的i-1盘子下面是i盘子的话,可以省掉一个不同的对数)
    j和k相不相同要分类讨论,因为是两种情况;
    因为允许放在“空地”上,所以j和k相同的情况也是ok的;
    这比汉诺塔的更“自由”一点;
    最后在f[cnt][1..n]中找最小值;

    NumberOf WA

    5

    Reviw

    按照递增的顺序枚举i;
    看看1..i这一些盘子在哪一堆上面;
    在哪一堆的情况都枚举一下;
    就能得到所有的情况了;
    主要是先想到,每个相邻的颜色不同的对数决定了最后答案;

    Code

    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define ms(x,y) memset(x,y,sizeof x)
    #define ri(x) scanf("%d",&x)
    #define rl(x) scanf("%lld",&x)
    #define rs(x) scanf("%s",x+1)
    #define oi(x) printf("%d",x)
    #define ol(x) printf("%lld",x)
    #define oc putchar(' ')
    #define os(x) printf(x)
    #define all(x) x.begin(),x.end()
    #define Open() freopen("F:\rush.txt","r",stdin)
    #define Close() ios::sync_with_stdio(0)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int N = 2500;
    const int M = 50;
    const int INF = 0x3f3f3f3f;
    
    int n,have[M+10][N+10],a[M+10][M+10],b[N+10],cnt;
    int f[N+10][M+10];
    vector <int> v[N+100];
    
    int main(){
        //Open();
        //Close();
        int kk = 0;
        while (~ri(n)){
            ms(f,INF),ms(have,0);;
            cnt = 0;
            rep1(i,1,N) v[i].clear();
            rep1(i,1,n){
                ri(a[i][0]);
                rep1(j,1,a[i][0]) {
                    ri(a[i][j]);
                    b[++cnt] = a[i][j];
                }
                a[i][0] = unique(a[i]+1,a[i]+1+a[i][0])-a[i]-1;
            }
    
            sort(b+1,b+1+cnt);
            cnt = unique(b+1,b+1+cnt) - b - 1;
    
            rep1(i,1,n){
                rep1(j,1,a[i][0]){
                    int x = lower_bound(b+1,b+1+cnt,a[i][j]) - b;
                    have[i][x] = 1;
                    v[x].pb(i);
                }
            }
    
            int len = v[1].size();
            rep1(i,0,len-1)
                f[1][v[1][i]] = len-1;
    
            rep1(i,2,cnt){
                int lenj = v[i].size(),lenk = v[i-1].size();
                rep1(jj,0,lenj-1){
                    int j = v[i][jj];
                    rep1(kk,0,lenk-1){
                        int k = v[i-1][kk];
                        if (j!=k)
                            f[i][j] = min(f[i][j],f[i-1][k] + (int) v[i].size() -
                                            (have[k][i]?1:0));
                        else{
                            int cost;
                            if ( (int) v[i].size() == 1)
                                cost = 0;
                            else
                                cost = (int) v[i].size();
                            f[i][j] = min(f[i][j],f[i-1][k] + cost);
                        }
                    }
                }
            }
            int ans = INF;
            rep1(i,1,n)
                ans = min(ans,f[cnt][i]);
            os("Case ");oi(++kk);os(": ");oi(ans*2-n+1);puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    Java后台获取微信小程序用户信息、openid
    异步上传excel带进度条
    iOS 手机App消息推送功能(后台Java实现)
    Java花样排序
    Java 按页拆分pdf
    Java实现按行拆分pdf
    mac 上将.pem文件转为.pub文件
    strust2的核心和工作原理
    InputStream流转字节数组
    合并InputStream流
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626135.html
Copyright © 2020-2023  润新知