饥饿的牛,单词的划分(基础dp)

饥饿的牛

牛在饲料槽前排好了队。饲料槽依次用1到N(1<=N<=2000)编号。每天晚上,一头幸运的牛根据约翰的规则,吃其中一些槽里的饲料。

约翰提供B个区间的清单。一个区间是一对整数start-end,1<=start<=end<=N,表示一些连续的饲料槽,比如1-3,7-8,3-4等等。牛可以任意选择区间,但是牛选择的区间不能有重叠。
当然,牛希望自己能够吃得越多越好。给出一些区间,帮助这只牛找一些区间,使它能吃到最多的东西。

在上面的例子中,1-3和3-4是重叠的;聪明的牛选择{1-3,7-8},这样可以吃到5个槽里的东西。

Input

第一行,整数B(1<=B<=1000)
第2到B+1行,每行两个整数,表示一个区间,较小的端点在前面。

Output

仅一个整数,表示最多能吃到多少个槽里的食物。

Sample Input 1

3
1 3
7 8
3 4

Sample Output 1

5

思路:

一维最大覆盖的dp,类似01背包

dp[i]表示以第i个槽作为当前所选的所有区间的最后一个的最右边那个槽;或者之前有一段空白的最大能吃到的东西数量;

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <map>
using namespace std;
const int MAXN = 1100;
int n;
int l[MAXN],r[MAXN],dp[2001];
int main(){
    cin>>n;
    for (int i = 1;i <= n;i++)
        cin >> l[i] >> r[i];
    for (int i = 1;i <= 2000;i++){//类似枚举体积 
        dp[i] = dp[i-1];//如果不装 
        for (int j = 1;j <= n;j++)
            if (r[j] == i)//如果装 
        		dp[i]=max(dp[i],dp[l[j]-1]+(r[j]-l[j]+1));           
    }
    cout<<dp[2000];
    return 0;
}

单词的划分

有一个很长的由小写字母组成的字符串。为了便于对这个字符串进行分析,需要将它划分成若干部分,每部分称为一个单词。出于减少分析量的目的,希望划分出的单词数越少越好。

Input

第1行1个字符串,长度不超过100。
第2行1个整数n,表示单词的个数,n<=100。
第3~n+2行,每行列出1个单词。

Output

一行一个正整数,表示字符串可以被划分成的最少的单词数。

Sample Input

realityour
5
real
reality
it
your
our
Sample Output

2

C++中substr函数的用法

#include<string>
#include<iostream>
using namespace std;
int main()
{
  string s("12345asdf");
  
  //获得字符串s中从第0位开始的长度为5的字符串
  string a = s.substr(0,5);     
  cout << a << endl;
}
//输出结果为:12345

思路:

d p [ i ] dp[i] dp[i] 表示所给字符串第 0 − i 0-i 0i位的子串可以被划分成的最少的单词数

具体见代码

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#include <set>
#include <map>
#include <sstream>
#define LL long long
#define mem(f, x) memset(f,x,sizeof(f)) 
#define fo(i,a,n) for(int i=a;i<n;++i)
#define fo2(i,a,n) for(int i=a;i<=n;++i)
const int INF = 0x3f3f3f3f;
using namespace std;
template<class T>inline void read(T &x){
    x=0; char c=getchar(); bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}

const int N=1005;
set<string> st[N];
string s, temp;
int dp[N];
int main(){
	cin >> s;
	int  m;
	read(m);
	fo(i,0,m){
		cin >> temp;
		st[temp.length()].insert(temp);
	}
	int l=s.length();
	fo(i,0,l){//枚举子串结尾 
		dp[i] = INF;
		fo2(j,1,i+1)//枚举子串长度,最短为1,最长为i+1
		//从s[i-j+1]开始,长度为j,结尾为s[i-j+1+(j-1)]即s[i]
			if(st[j].count(s.substr(i-j+1,j)))//如果这个子串出现在了单词集合里	
				//如果子串达到最长(从头到i是一个单词),那么它本身就是最小值,即1(防止越界,特殊写一下) 
				//否则,就从子串开始处的dp值+1即可 
				dp[i]=min(dp[i],(j==i+1)?1:dp[i-j]+1);//条件转移方程				
	}
	cout<<dp[l-1];
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值