【转】毛虫算法——尺取法
转自http://www.myexception.cn/program/1839999.html
妹子满分~~~~
毛毛虫算法——尺取法
有这么一类问题,需要在给的一组数据中找到不大于某一个上限的“最优连续子序列”
于是就有了这样一种方法,找这个子序列的过程很像毛毛虫爬行方式,我管它叫毛毛虫算法,比较流行的叫法是“尺取法”。
喏,就像图里的妹纸一样~
还是举个栗子:
Poj3061
给长度为n的数组和一个整数m,求总和不小于m的连续子序列的最小长度
输入
n = 10,m = 15
5 1 3 5 10 7 4 9 2 8
输出
2
那么我们先用sum存当前这个子序列的和,从左边第一个数来存,直到这个子序列的和大于等于m为止,再记录下当前长度。
其实相当于当不满足条件就入队,然后得到队列长度,再将队首元素出队,再进行下一次的入队,直到满足条件再次出队,并且将这一次的长度与历史最短长度进行取舍,最后扫到最后的元素却无法再满足入队条件的时候就结束,此时用O(n)的时间就可以得到答案。
如下,我把样例用毛毛虫爬一遍,下划线的是当前“毛毛虫着地”也就是刚好满足题意的子序列的地方:
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
5 1 3 5 10 7 4 9 2 8
祖传代码。。。
C++
/*************************************************************************
> File Name: main.cpp
> Author: haoran
> Created Time: 2015年01月19日 星期一 21时04分36秒
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <algorithm>
using namespace std;
int a[200000];
int main()
{
// freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(false);
int n,max,sum,T; while(cin>>T)
{
while(T--)
{
cin>>n>>max;
for(int i = 0 ; i < n ; i++)
cin>>a[i];
int i = 0,j = 0,sum = 0,ans = n+1;
while(1)
{
while(j < n && sum <= max)
sum += a[j++]; if(sum < max) break;
ans = min(j-i,ans);
sum -= a[i++];
}
if(ans > n)
ans = 0;
printf("%d\n",ans);
}
}
return 0;
}
java大法的
import java.util.Scanner;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner cin = new Scanner(System.in);
int a[] = new int[100010];
int T = cin.nextInt();
for(int ii = 0 ; ii < T ; ii++)
{
int n = cin.nextInt();
int m = cin.nextInt();
for(int i = 0 ; i < n ; i++)
a[i] = cin.nextInt();
int l = 0,r = 0,ans = m+1,sum = 0;
while(true)
{
while(r < n && sum < m)
sum += a[r++];
if(sum < m)
break;
ans = min(ans,r-l);
sum -= a[l++];
}
if(ans > n)
ans = 0;
System.out.println(ans);
}
}
private static int min(int ans, int sum) {
// TODO Auto-generated method stub
return ans < sum ? ans : sum;
}
}
买一送一,再给大家一颗栗子;
Poj3320
这道题费点脑子,大意:
一个考前一天看一整本书发呆的学渣,找学霸划知识点,学霸告诉他每一页的知识点(每一页只有一个知识点而且页与页之间可以重复知识点!),每一个知识点都用一个数字表示,给你这本书一共有n页厚,学渣很懒,只想读连续若干页的书,还不想看太多页,所以要你帮他找覆盖所有出现过的知识点的连续页的页数最薄有几页。
输入
n = 5
1 8 8 8 1
输出
2
很显然一共有5页书,却只有2个知识点,想读就读前两页,所以就输出2页。先想想需要解决什么问题:
1.要解决出现一共多少个知识点
2.根据当前子序列包含的知识点数来入队、出队
其实就这样。
第一个问题其实可以用set来解决,知识点数量就是set的size大小。
下一个问题其实可以用map来存,存每一页出现的知识点在这个子序列中出现的次数,如果是0的话就把这个知识点放进来并++,直到所有知识点覆盖为止。
在所有知识点覆盖的基础上出队,直到某一个知识点在子序列的出现次数为0的时候,再从后面入队,并在这些操作中记录下最少页数就可以了,剩下的和第一颗栗子一个味道。
祖传C++代码如下~
#include <iostream>
#include <map>
#include <set>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
using namespace std;
int n,m,a[1000010];
void solve()
{
set<int> all ;
map<int,int>cnt;
for(int i = 0 ; i < n ; i++)
{
scanf("%d",&a[i]);
all.insert(a[i]);
} m = all.size();
int l = 0 , r = 0 , ans = n+1,sum = 0;
while(1)
{
while(r < n && sum < m)
if(cnt[ a[r++] ]++ == 0)
sum++;
if(sum < m)break;
ans = min(ans,r-l);
if(--cnt[ a[l++] ] == 0)
sum--;
}
printf("%d\n",ans);
}
int main()
{
#ifdef H_R
freopen("in.txt","r",stdin);
#endif // H_R while(scanf("%d",&n)!=EOF)
{
solve();
}
return 0;
}
【转】毛虫算法——尺取法的更多相关文章
- 【算法•日更•第二十三期】数据结构:two-pointer(尺取法)&莫队
▎引入 ☞『例题』 一道十分easy的题: 洛谷P1638 长度为n的序列,m种数 找一个最短区间,使得所有数出现一遍 n≤1e6 ,m≤2e3. ☞『分析』 这道题非常的简单,但是如果不会two-p ...
- HDU 5358 尺取法+枚举
题意:给一个数列,按如下公式求和. 分析:场上做的时候,傻傻以为是线段树,也没想出题者为啥出log2,就是S(i,j) 的二进制表示的位数.只能说我做题依旧太死板,让求和就按规矩求和,多考虑一下就能发 ...
- Codeforces Round #364 (Div.2) C:They Are Everywhere(双指针/尺取法)
题目链接: http://codeforces.com/contest/701/problem/C 题意: 给出一个长度为n的字符串,要我们找出最小的子字符串包含所有的不同字符. 分析: 1.尺取法, ...
- poj3061 Subsequence(尺取法)
https://vjudge.net/problem/POJ-3061 尺取发,s和t不断推进的算法.因为每一轮s都推进1所以复杂度为O(n) #include<iostream> #in ...
- POJ 3061 Subsequence(尺取法)
Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 18145 Accepted: 7751 Desc ...
- POJ 3061 Subsequence ( 尺取法)
题目链接 Description A sequence of N positive integers (10 < N < 100 000), each of them less than ...
- 题解报告:poj 3061 Subsequence(前缀+二分or尺取法)
Description A sequence of N positive integers (10 < N < 100 000), each of them less than or eq ...
- POJ 3061 Subsequence 二分或者尺取法
http://poj.org/problem?id=3061 题目大意: 给定长度为n的整列整数a[0],a[1],--a[n-1],以及整数S,求出总和不小于S的连续子序列的长度的最小值. 思路: ...
- POJ 3061 Subsequence 尺取法 挑战146页
---恢复内容开始--- Subsequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 10487 Accept ...
随机推荐
- React基础篇学习
到今天为止, 使用react已经一年了, 现在整理一下入门时的一些重要知识, 帮助想要学习react的同学们理解某些内容. React 元素 React 元素,它是 React 中最小基本单位,我们可 ...
- 【洛谷p1781】宇宙总统
宇宙总统[题目链接] 关于题目算法,其实就是考排序,那我们直接sort不就好啦,显然不能. 这个题让我重新认识了cmp函数: 以下是我的心路历程: 看到这个题,嗯?这么简单的吗,我直接sort不就好啦 ...
- 最长不下降/不上升子序列&&最长上升/下降子序列
最长不下降/不上升子序列&&最长上升/下降子序列 struct cmp1{bool operator()(int a,int b){return a>b;}}; int main ...
- Boruvka
大概是这样的:一开始图中有\(n\)个连通块,每次操作我们选出各个连通块连出去的最短的边(如果有相同边权的边的话可以把序号作为第二关键字),然后把这些边加入最小生成树. 最坏的情况下每次操作都会让当前 ...
- C++学习——在C文件中调用C++文件中的函数
1.CPP文件中的内容 #include "mytest.h" #include <iostream> using namespace std; int add(con ...
- 读取CSV文件存入map中(C++)
自己平时操作文件用的不多,今天小伙伴让帮忙写一下这个,顺便记一下.实现功能:从"翻译.csv"文件中读取出字符串,以","作为分隔符,将每一行对应存入map中. ...
- 26. Remove Duplicates from Sorted Array(代码思路新奇)
Given a sorted array, remove the duplicates in-place such that each element appear only once and ret ...
- P1398 [NOI2013]书法家
传送门 就是个普及组 $dp$ 合集,把 $NOI$ 从左到右拆成 $9$ 个部分,每个部分都可以分别 $dp$ 除了 $N$ 的中间部分比较恶心以外其他都还好,自己推一下然后就知道转移,就 $N$ ...
- Homebrew学习(二)之安装、卸载、更新
安装 1.网上的安装方法都是用curl,从官网找到命令复制到终端,然后回车,结果报错请求超时 /usr/bin/ruby -e "$(curl -fsSL https://raw.githu ...
- npm学习(七)之如何发布包、更新发布包、删除发布包
前言 我们经常使用npm来下载别人的模块或者说包,那么我们如何将自己写的模块上传到npm呢? 了解npm政策 在开始之前,最好回顾一下npm的政策,以防您对站点礼仪.命名.许可或其他指导原则有疑问. ...