饥饿的牛
牛在饲料槽前排好了队。饲料槽依次用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 0−i位的子串可以被划分成的最少的单词数
具体见代码
代码:
#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;
}