H - Checker FZU - 2041

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H - Checker FZU - 2041相关的知识,希望对你有一定的参考价值。

H - Checker FZU - 2041

题意:

一个长度为n的01串,现在能将里面的1移动m次,问最长的连续0是多长

题解:

没想出来,看了其他人代码,就是对于每个0空间进行扩充,然后记录每次扩充的最大值
关键在于扩充的细节:
我们每次锁定一个连续的0的左右端点(图中的left和right)
然后看left和right分别向外找最近的0,我们可以通过下图看出,左侧长度为lena可以找到0,右侧lenb可以找到0,lena<lenb,所以我们移动左侧
每次移动也是缓慢移动,我们让i和j进行交换,然后看left-1(即k的位置)是否为0,如果是0,left就向左移动,相当于扩大区间,
为什么要先交换i和j呢?因为要扩大范围,只能先换走j,再换走k,一步一步来,不能着急,每次移动都会消耗步数
在这里插入图片描述
这个思路很妙

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
 
typedef long long LL;
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int MAXN = 500 + 10;
int t, len, step;
char G[MAXN], CG[MAXN];
 
int Calc(int left, int right) {
    strcpy(CG, G);
    int cnt = step;
    int low = left - 1, high = right + 1;
    while (cnt--) 
	{
        if (low - 1 < 0 && high + 1 >= len) break;
        for (;;) 
		{
            if (low - 1 < 0 && high + 1 >= len) break;
 
            int lena = INF, lenb = INF;
            bool yes = false;
 
            if (low - 1 >= 0 && CG[low - 1] == '0') {//记录两个0之间相隔1的数量 
                lena = left - (low - 1);
                yes = true;
            } 
 
            if (high + 1 < len && CG[high + 1] == '0') {
                lenb = high + 1 - right;
                yes = true;
            }
            
            if (!yes) {//如果low和high还没找到0,继续向外找 
                --low;
                ++high;
                continue;
            }
 
            if (lena < lenb) {//相隔1最少的 
                swap(CG[low], CG[low - 1]);
                if (CG[left - 1] == '0') {//查看left是否可以向左扩展 
                    --left;
                }
            } 
			else {
                swap(CG[high], CG[high + 1]);
                if (CG[right + 1] == '0') {
                    ++right;
                }
            }
 
            low = left - 1;
            high = right + 1;
            break;
        }
    }
    return right - left + 1;
}
 
int main() {
    scanf("%d", &t);
    int cas = 0;
    while (t--) {
        scanf("%d%d%s", &len, &step, G);
        int ans = 0;
        for (int i = 0; i < len;) {
            if (G[i] == '0') {
                int j = i;
                while (j + 1 < len && G[j + 1] == '0') { ++j; }//每次找到连续0的左右端点 
                ans = max(ans, Calc(i, j));
                i = j + 1;
            } 
			else {
                ++i;
            }
        }
        printf("Case %d: %d\\n", ++cas, ans);
    }
    return 0;
}

以上是关于H - Checker FZU - 2041的主要内容,如果未能解决你的问题,请参考以下文章

FZU 2150 枚举+BFS

AcWing 2041. 干草堆(差分)

hdu2041超级楼梯(DP)

FZU 2169 shadow

FZU 2122 又见LKity

2041-超级楼梯(斐波那契)/(排列组合)