79-拦截导弹
内存限制:64MB 时间限制:3000ms Special Judge: No
题目描述:
某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于等于前一发的高度。某天,雷达捕捉到敌国导弹来袭。由于该系统还在试用阶段,所以只用一套系统,因此有可能不能拦截所有的导弹。
输入描述:
输出描述:
样例输入:
2 8 389 207 155 300 299 170 158 65 3 88 34 65
样例输出:
6 2
#include <iostream>
using namespace std;
int main()
{
int t,n,a[20],dp[20];
cin>>t;
while(t--)
{
int maxx=-1;
cin>>n;
for (int i=0; i<n; i++)
cin>>a[i];
fill(dp,dp+20,1);
for (int i=0; i<n; i++)
for (int j=0; j<i; j++)
if(a[j]>a[i])
{
dp[i]=max(dp[i],dp[j]+1);
if(dp[i]>maxx)
maxx=dp[i];
}
cout<<maxx<<endl;
}
return 0;
}
17-单调递增最长子序列
内存限制:64MB 时间限制:3000ms Special Judge: No
题目描述:
如:dabdbf最长递增子序列就是abdf,长度为4
输入描述:
输出描述:
样例输入:
3 aaa ababc abklmncdefg
样例输出:
1 3 7
题解:状态转移方程:dp[i]=max(dp[j]), dp[j]<dp[i],j<i。
#include <iostream>
using namespace std;
int main()
{
int t,dp[10001];
string str;
cin>>t;
while(t--)
{
int maxx=1;
cin>>str;
fill(dp,dp+10001,1);
for (int i=0; i<str.size(); i++)
for (int j=0; j<i; j++)
if(str[j]<str[i])
{
dp[i]=max(dp[i],dp[j]+1);
maxx=max(dp[i],maxx);
}
cout<<maxx<<endl;
}
return 0;
}
37-回文字符串
内存限制:64MB 时间限制:3000ms Special Judge: No
题目描述:
输入描述:
输出描述:
样例输入:
1 Ab3bd
样例输出:
2
题解:求最长公共子序列。添加字符=原串长-最长公共子序列长。
dp[i][j]表示长为i的s1前缀和长为j的s2前缀的最长公共子序列长。
状态转移方程:s1[i]==s2[j] dp[i][j]=dp[i-1][j-1]+1;
s1!=s2[j] dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
#include <iostream>
#include <algorithm>
using namespace std;
int dp[1001][1001];
int main()
{
int t;
string s1,s2;
cin>>t;
while(t--)
{
cin>>s1;
int len=s1.size();
s2=s1;
reverse(s2.begin(),s2.end());
fill(dp[0],dp[0]+(len+1)*(len+1),0);
for (int i=0;i<len;i++)
for (int j=0;j<len;j++)
{
if(s1[i]==s2[j])
dp[i+1][j+1]=dp[i][j]+1;
else
dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]);
}
cout<<len-dp[len][len]<<endl;
}
return 0;
}
阅读量:238
104-最大和
内存限制:64MB 时间限制:1000ms Special Judge: No
题目描述:
给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。
例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
其最大子矩阵为:
9 2
-4 1
-1 8
其元素总和为15。
输入描述:
输出描述:
样例输入:
1 4 4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
样例输出:
15
题解:将二维压缩成一维,然后转化为求最大子串和。
#include <iostream>
using namespace std;
int main ()
{
int t,n,m,a[101][101];
cin>>t;
while(t--)
{
cin>>n>>m;
fill(a[0],a[0]+101*101,0);
for (int i=1; i<=n; i++)
for (int j=1; j<=m; j++)
{
cin>>a[i][j];
a[i][j]+=a[i-1][j];//求第j列的前i项和。
}
int mx=a[1][1];
for (int i=1; i<=n; i++)
for (int j=i; j<=n; j++)
{
int sum=0;
for (int k=1; k<=m; k++)
{
int tmp=a[j][k]-a[i-1][k];
sum=(sum>=0?sum:0)+tmp;
mx=max(mx,sum);
}
}
cout<<mx<<endl;
}
return 0;
}
325-zb的生日
内存限制:64MB 时间限制:3000ms Special Judge: No
题目描述:
输入描述:
输出描述:
样例输入:
5 5 8 13 27 14
样例输出:
3
题解:若想两部分尽量相等,那么只要考虑一个部分,让它接近它们总和的一半。
dp[j]表示重量为j能否凑成,当然j最大为sum/2。
状态转移方程:if(dp[j-w[i]]==1)dp[j]=dp[j-w[i]]。
#include <iostream>
int dp[100001];
using namespace std;
int main ()
{
int n,w[21],m,sum;
while(cin>>n)
{
m=sum=0;
fill(dp,dp+100001,0);
for (int i=0; i<n; i++)
{
cin>>w[i];
sum+=w[i];
}
dp[0]=1;
for (int i=0; i<n; i++)
{
(m+w[i]<sum/2)?m+=w[i]:m=sum/2;
for (int j=m; j>=w[i]; j--)
if(dp[j-w[i]])
dp[j]=1;
}
int i;
for (i=sum/2;!dp[i];i--);//找出最接近sum/2的重量。
cout<<sum-2*i<<endl;
}
return 0;
}
168-房间安排
内存限制:64MB 时间限制:3000ms Special Judge: No
题目描述:
2010年上海世界博览会(Expo2010),是第41届世界博览会。于2010年5月1日至10月31日期间,在中国上海市举行。本次世博会也是由中国举办的首届世界博览会。上海世博会以“城市,让生活更美好”(Better City,Better Life)为主题,将充分探索21世纪城市生活。
这次世博会总投资达450亿人民币,创造了世界博览会史上的最大规模记录。吸引200个国家和国际组织参展。预计有7000万人次的参观者。
为了更好地接待在这期间来自世界各地的参观者,如何合理安排各宾馆的住房问题提到了日程。组委会已接到了大量的客户住宿定单,每张定单的内容包括要住宿的房间数,开始住宿时间和要住的天数。为了便于整个城市各宾馆的管理,组委会希望对这些定单进行安排,目的是用尽可能少的房间来满足这些定单,以便空出更多的房间用于安排流动游客。
组委会请求DR.Kong来完成这个任务,对这些定单进行合理安排,使得满足这些定单要求的房间数最少。
假设:某个定单上的游客一旦被安排到某房间,在他预定住宿的期间内是不换房间的。为了简化描述,定单上的开始住宿时间为距离现在的第几天。例如,定单为(10,30,5)表示游客要求使用10个房间,第30天开始连住5天。
输入描述:
输出描述:
样例输入:
1 3 3 10 4 4 9 3 3 12 6
样例输出:
7
题解:定向思维了,开始以为是稍微复杂的贪心。其实只要在对应的区间进行叠加。
#include <iostream>
using namespace std;
int s[200];
int main ()
{
int t;
cin>>t;
while(t--)
{
fill(s,s+200,0);
int n,maxx=-1;
cin>>n;
for (int i=0;i<n;i++)
{
int a,b,c;
cin>>a>>b>>c;
for (int j=b;j<b+c;j++)
{
s[j]+=a;
if(s[j]>maxx)
maxx=s[j];
}
}
cout<<maxx<<endl;
}
return 0;
}
311-完全背包
内存限制:64MB 时间限制:4000ms Special Judge: No
题目描述:
直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是c,价值是w。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。本题要求是背包恰好装满背包时,求出最大价值总和是多少。如果不能恰好装满背包,输出NO
输入描述:
输出描述:
样例输入:
2 1 5 2 2 2 5 2 2 5 1
样例输出:
NO 1
题解:模板,由于要刚好装满,所以除dp[0]=0,其他的都赋值很小的负数。
#include <iostream>
using namespace std;
int dp[50005],inf=0x3f3f3f3f;
int main ()
{
int t;
cin>>t;
while(t--)
{
fill(dp,dp+50005,-inf);
dp[0]=0;
int m,V,w[2001],v[2001];
cin>>m>>V;
for (int i=0;i<m;i++)
cin>>w[i]>>v[i];
for (int i=0;i<m;i++)
for (int j=w[i];j<=V;j++)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
if(dp[V]>0)
cout<<dp[V]<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
737-石子合并(一)
内存限制:64MB 时间限制:1000ms Special Judge: No
题目描述:
输入描述:
有多组测试数据,输入到文件结束。 每组测试数据第一行有一个整数n,表示有n堆石子。 接下来的一行有n(0< n <200)个数,分别表示这n堆石子的数目,用空格隔开
输出描述:
输出总代价的最小值,占单独的一行
样例输入:
3 1 2 3 7 13 7 8 16 21 4 18
样例输出:
9 239
题解:dp[i][j]表示:i到j合并总代价最小。dp[i][j]=min(dp[i][k]+dp[k+1][j]+i到j合并代价),i<=k<j;
#include <iostream>
using namespace std;
const int inf=0x3f3f3f3f;
int dp[201][201],sum[201];
int main ()
{
int n,m;
while(cin>>n)
{
sum[0]=0;
for (int i=1; i<=n; i++)
{
cin>>m;
sum[i]=sum[i-1]+m;
dp[i][i]=0;//不能合并
}
for (int len=1; len<n; len++)
{
for (int i=1; i<=n-len; i++)
{
int j=i+len;
dp[i][j]=inf;
for (int k=i;k<j;k++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
cout<<dp[1][n]<<endl;
}
return 0;
}