4.Coincidence
问题描述:find a longest common subsequence of two strings.(找到两个字符串的最长公共子序列)
输入:first and second line of each input case contain two strings of lowercase character a...z. there are no spaces before, inside or after the strings. length of the strings do not exceed 100.(第一行第二行分别输入两个包含a...z的字符串,不包含空格,字符串长度不超过100)
输出:for each case, output k--the length of a longest common subsequence in one line(每一种情况,输出最长公共子序列 的长度)
//最长公共子序列长度
#include<stdio.h>
#include<string.h>
int buf[101][101];
int max(int a, int b){return a>b?a:b;}
char first[101],second[101];
int main(){
while(scanf("%s%s",first,second)!=EOF){
int l1=strlen(first);
int l2=strlen(second);
for(int i=0;i<l1;i++)buf[i][0]=0;
for(int j=0;j<l2;j++)buf[0][j]=0;
for(int i=1;i<l1;i++){
for(int j=1;j<l2;j++){
if(first[i]==second[j])buf[i][j]=buf[i-1][j-1]+1;
else buf[i][j]=max(buf[i-1][j],buf[i][j-1]);
}
}
printf("最长公共字符串长度为:%d\n",buf[l1-1][l2-1]);
}
return 0;
}
背包问题——0-1背包、完全背包、多重背包
5.采药问题(0-1背包问题:每种草药有两种状态,在背包中;不在背包中)问题描述:在固定的时间里采一些草药,使得草药的价值最大
输入:输入的第一行有两个整数T(1<=T<=1000)和M(1<=M<=100),T代表总共能够用来采药的时间,M代表山洞里草药的数目。接下来的M行每行包括两个在1到100之间的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出:可能有多组测试数据,对于每组数据,输出只包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
//0-1背包问题
#include<stdio.h>
int buf[101][1001];//总时间不超过j的情况下前i个草药所能达到的最大价值
/*
若第一棵草药所需时间超过总时间则不采,若某一棵草药时间短于剩余时间,则将此草药采下,满足采此草药的时间为当前时间减去采此草药所耗费的时间,
每一个buf表示当前时刻最多可以有多少价值
*/
int max(int a,int b){return a>b?a:b;
}
int main(){
int T,M;
while(scanf("%d%d",&T,&M)!=EOF){
int time[101],value[101];
for(int i=1;i<=M;i++){
scanf("%d%d",&time[i],&value[i]);
}
for(int j=0;j<=T;j++){
buf[0][j]=0;
}
for(int i=1;i<=M;i++){
for(int j=T;j>=time[i];j--){//j表示当前时刻,要保证还剩余的时间大于第i个草药所耗费的时间
buf[i][j]=max(buf[i-1][j-time[i]]+value[i],buf[i-1][j]);//若第i个草药在背包中,原所用时间不超过j-time[i] ,新价值加上第i个草药的价值;
//若第i个草药不在背包中,原所用时间不超过j
}
for(int j=time[i]-1;j>=0;j--){
buf[i][j]=buf[i-1][j];
}
}
printf("草药最大价值为:%d",buf[M][T]);
}
return 0;
}
输入:70 3\n71 100\n69 1\n1 2\n
输出:3
buf | 0 | 1 | 2 | 3 | ... | 68 | 69 | 70 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
3 | 0 | 1 | 2 | 3 | 3 | 3 | 3 | 3 |
若用一维数组表示前i种状态的最大价值,则状态转移函数为:buf[j]=max{buf[j-time[i]]+value[i],buf[j]}
//0-1背包问题
#include<stdio.h>
int buf[1001];//总时间不超过j的情况下前i个草药所能达到的最大价值
/*
若第一棵草药所需时间超过总时间则不采,若某一棵草药时间短于剩余时间,则将此草药采下,满足采此草药的时间为当前时间减去采此草药所耗费的时间,
每一个buf表示当前时刻最多可以有多少价值
*/
int max(int a,int b){return a>b?a:b;
}
int main(){
int T,M;
while(scanf("%d%d",&T,&M)!=EOF){
int time[101],value[101];
for(int i=1;i<=M;i++){
scanf("%d%d",&time[i],&value[i]);
}
for(int j=0;j<=T;j++){
buf[j]=0;
}
for(int i=1;i<=M;i++){
for(int j=T;j>=time[i];j--){//j表示当前时刻,要保证还剩余的时间大于第i个草药所耗费的时间
buf[j]=max(buf[j-time[i]]+value[i],buf[j]);//若第i个草药在背包中,原所用时间不超过j-time[i] ,新价值加上第i个草药的价值;
//若第i个草药不在背包中,原所用时间不超过j
}
}
printf("草药最大价值为:%d",buf[T]);
}
return 0;
}
问题描述:there is a piggy-bank, but it is not possible to determine how much money is inside. the only way is to weigh the piggy-bank and try to guess how many coins are inside. we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency. then there is some minimum amount of money in the piggy-bank that we can guarantee. find out the minimum amount of cash inside the piggy-bank.
输入:the input consists of T test cases. the number of them is given on the first line of the input file. each test case begins with a line containing two integers E and F. they indicate the weight of an empty pig and of the pig filled with coins. both weights are given in grams. no pig weigh more than 10kg, that means 1<=E<=F<=10000. on the second line of each test case, there is an integer number N(1<=N<=500) that gives the number of various coins used in the given currency. Following this are exactly N lines, each one coin type. these lines contain two integers each, P and W(1<=P<=50000,1<=W<=10000).P is the value of the coin in monetary unit, W is weight in grams.
输出:one line of output for each test case. the line must contain the minimum amount of money.
//完全背包问题
#include<stdio.h>
#define INF 0x7fffffff
int min(int a,int b){return a<b?a:b;}
struct E{
int value;
int weight;
}CoinType[501];
int buf[10001];//状态
int main(){
int T;//number of cases
scanf("%d",&T);
while(T--){
int E,F;//1<=E<=F<=10000,w eight of empty and filled with coins
scanf("%d%d",&E,&F);
F=F-E;//硬币的总重量
int n;//number of coin types
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&CoinType[i].value,&CoinType[i].weight);
}
for(int i=0;i<=F;i++){
buf[i]=INF;//为每一种状态赋初值
}
buf[0]=0;
for(int i=1;i<=n;i++){
for(int j=CoinType[i].weight;j<=F;j++){//一枚该硬币的重量为cointype[i].weight,每次增加一枚硬币都要保证
if(buf[j-CoinType[i].weight]!=INF){
buf[j]=min(buf[j],buf[j-CoinType[i].weight]+CoinType[i].value);//前一个状态加上一枚第i硬币和原有值得最小值
}
}
}
if(buf[F]!=INF){
printf("the minimum amount of money in the piggy-bank is %d.\n",buf[F]);
}
else puts("this is impossible");
}
return 0;
}
7.有限资金采购粮食问题(多重背包问题,每种物品的数量为k)
问题描述:一共有资金n元,市场有m种大米,每种大米都是袋装产品,价格不等,并且只能整袋购买,请问用有限的资金最多能够采购多少公斤粮食?
输入:输入数据首先包含一个正整数c,表示有c组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100,1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量和对应种类大米的袋数
输出:对于每组测试数据,请输出能够购买大米的最多重量。可以假设经费买不光多有大米,并且经费可以用不完,每个实例输出一行。
//多重背包问题
#include<stdio.h>
struct E{
int w;//price of rice
int v;//weight of rice
}list[2001];
int dp[101];
int max(int a,int b){
return a>b?a:b;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int s,n;
scanf("%d%d",&s,&n);
int cnt=0;//拆分后物品总数
for(int i=1;i<=n;i++){
int v,w,k;
scanf("%d%d%d",&w,&v,&k);
int c=1;
while(k-c>0){
k-=c;
list[++cnt].w=c*w;
list[cnt].v=c*v;
c*=2;
}
list[++cnt].w=w*k;
list[cnt].v=v*k;
}
for(int i=1;i<=s;i++)dp[i]=0;
for(int i=1;i<=cnt;i++){
for(int j=s;j>=list[i].w;j--){
dp[j]=max(dp[j],dp[j-list[i].w]+list[i].v);
}
}
printf("%d\n",dp[s]);
}
return 0;
}
多重背包问题介于0-1背包和完全背包之间:有容积为v的背包,给定一些物品,每种物品包含体积w、价值v和数量k,求背包能够装下的最大价值总量。将多重背包问题转换成0-1背包问题,普通转换可能会超时,这里利用二进制转换,每组物品包含的原物品个数分别为1、2、4、8...k-2^c+1,其中c为使
k-2^c+1大于0的最大整数