二分查找+DP
动态规划算法及经典例题: https://blog.csdn.net/zw6161080123/article/details/80639932.
(花时间掌握,上面这个博客对于动态规划的基本思想和转化方程讲述很详细,对动态规划的典型用法和例题也讲解十分清楚,对本次的题集有很大帮助)
A
题意
n个班每个班的学生报名ABC三种课程,求n个班中 max(只报名A的人+只报名B的人+只报名C+只报名AC+只报名BC+只报名AB+只报名ABC的人)数据有可能是假的,假的数据直接忽略掉,保证一定有一个真的数据
思路
报名abc的人数一定是只报名abc的人数,那么只报名ab的人数就是 报名ab人数 - 只报名abc人数,ac,bc同理
只报名a的人数一定是 报名a的人数- 只报名ac的人数-只报名ab的人数 - 只报名abc的人数,b,c同理
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=100007;
int n;
int main()
{
int t;
scanf("%d", &t);
while (t > 0)
{
t--;
scanf("%d", &n);
int ans = -1;
for (int i=0; i<n; i++)
{
int a, b, c, ab, ac, bc, abc;
int a1, b1, c1, ab1, ac1, bc1, abc1;
scanf("%d%d%d%d%d%d%d", &a,&b,&c,&ab,&bc,&ac,&abc);
abc1 = abc;
ab1 = ab - abc1;
ac1 = ac - abc1;
bc1 = bc - abc1;
a1 = a - ab1 - ac1 - abc1;
b1 = b - ab1 - bc1 - abc1;
c1 = c - ac1 - bc1 - abc1;
if (a1 < 0 || b1 < 0 || c1 < 0 || ab1 < 0 ||
bc1 < 0 || ac1 < 0 || abc1 < 0)//判断数据是否正确
{
continue;
}
ans = max(ans, a1+b1+c1+ab1+bc1+ac1+abc1);
}
cout << ans << endl;
}
return 0;
}
B
题意
用规定数目的猫粮换取最大数目的豆子,每个测试样例先给出规定的猫粮和房间数,后面给出每个房间的豆子和所需消耗的猫粮,直到输入-1 -1结束
思路
题目规定可以部分猫粮换取房间中的部分豆子,那么可以将每个房间的豆子和所需猫食做比例当成性价比,按性价比进行排序,按性价比排名依次获取豆子消耗猫粮,直到所剩猫粮无法完全获取某个房间内所有豆子时,则将所剩猫粮按比例换取相应豆子,求出最大豆子数
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1007;
int M,N; //M-catfood N-room
struct node
{
int j; //javabean
int f; //cat food
double rate; //两者比例
} a[maxn];
double cmp(node a,node b)
{
return a.rate>b.rate;
}
int main()
{
double sum;
while(cin>>M>>N)
{
sum=0;
if(M==-1 && N==-1)
break;
for(int i=0; i<N; i++)
{
cin>>a[i].j>>a[i].f;
a[i].rate=a[i].j*1.0/a[i].f*1.0;
}
sort(a,a+N,cmp);//C++sort排序,与C的快排相似
for(int i=0; i<N; i++)
{
if(M>=a[i].f)
{
M-=a[i].f;
sum+=a[i].j;
}
else if(M<a[i].f && M>0)
{
sum+=M*a[i].rate;
break;
}
}
printf("%.3lf\n",sum);
}
return 0;
}
C
题意
合理选择电视节目,使得可以观看最多的节目
思路
给出了每个节目的开始和结束时间,要求尽可能观看更多节目,可以把节目进行排序,按结束时间从小到大进行排序,当结束时间相等时,按开始时间由大到小排序(运用sort排序,sort排序使用方法自己掌握),再依次遍历,判断能否观看当前节目,并更新结束时间
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=107;
struct TV
{
int start,endup;
}x[maxn];
bool cmp(const TV &p1,const TV &p2)
{
if(p1.endup!=p2.endup)
return p1.endup<p2.endup;
else
return p1.start>p2.start;
}
int main()
{
int n;
while(cin>>n)
{
int sum=1;
if(n==0)
break;
for(int i=0;i<n;i++)
cin>>x[i].start>>x[i].endup;
sort(x,x+n,cmp);
int t=x[0].endup;//第一个节目的结束时间
for(int i=1;i<n;i++)
{
if(x[i].start>=t)//如果后一个节目的开始时间大于前面的结束时间,代表后一个节目可以观看
{
sum++;
t=x[i].endup;//更新结束时间
}
}
cout<<sum<<endl;
}
return 0;
}
D
题意
农夫有N间牛舍,牛舍排在一条线上,第i号牛舍在xi的位置。他的小牛彼此之间都会互相攻击。农夫为了防止牛之间互相伤害,决定要把每头牛都放在离其他牛尽可能远的牛舍。牛的数量是C,会给出n间牛舍的位置。
我们要使每两头牛的距离尽可能大,然后找出这些距离中的最小值。也就是离得最近的两头牛之间的距离。
思路
我们可以利用二分和贪心结合的思想,通过二分来猜测到一个值,然后进行判断,如果答案可行,则猜的距离可以再大些,如果答案不可行,则猜的距离就要再小些。在判断答案是否可行时,可以用cnt来记录匹配到槽的奶牛数,先将第一头奶牛放在第一个槽,然后依次枚举每个槽,当枚举的槽与前一个放奶牛的槽的距离>=猜的答案时,cnt++,最后如果cnt>=牛的数量,说明这个距离可行,如果cnt<牛的数量,说明这个距离太大了。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=100007;
int n,c;
long long a[maxn];//数据大,用 longlong
int check(long long mid)
{
int cnt=1; //记录牛的数量
int crw=a[0]; //第一头牛肯定是放在最边上第一个位置。
for(int i=1; i<n; i++)
{
if(a[i]-crw>=mid) //如果槽到前一头牛之间的距离大于mid,就可以将牛放到这个槽中
{
cnt++;
crw=a[i];
}
if(cnt>=c)return 1;
}
return 0;
}
int main()
{
cin>>n>>c;
for(int i=0; i<n; i++)
cin>>a[i];
sort(a,a+n);
long long l=a[0],r=a[n-1];
while(r-l>1)//二分定距离
{
long long mid=(l+r)/2;
if(check(mid))l=mid;//如果可以放牛的数量比给定的大,说明距离(mid)小了,需要放大
else r=mid;//反之放小
}
cout<<l<<endl;
return 0;
}
E
题意
有n段长度分别为Li的电缆,要求把它们分割成K条长度为X的电缆,问X的最大值为多少。
思路
将X视为变量,可知它的范围为0~max; 那么问题就变成了电缆长度取X时,所得的电缆条数大于,还是等于,或小于K的问题。 用二分查找法能很快的找出K的值,不过要注意精度(吐槽double的精度问题,实在是见鬼的存在),直接输出时会四舍五入,五入时的结果肯定是错的,注意向下取整。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=100007;
double a[maxn];
int n,k;
bool dix(double x)
{
int num=0;
for(int i=0; i<n; ++i)
num+=(int)(a[i]/x);//取整相当于向下取整,如果四舍五入那么长度就会超出
return num>=k;//满足条件是返回true,不满足返回false
}
int main()
{
while(scanf("%d %d",&n,&k)!=EOF)
{
for(int i=0; i<n; ++i)
scanf("%lf",&a[i]);
double left=0,right=100001,mid;//题目规定最大长度为100公里
int i=1000;//进行1000次二分查找
while(i--)
{
mid=(left+right)*1.0/2;
if(dix(mid))
left=mid;
else
right=mid;
}
printf("%0.2f\n",floor(right*100)/100);//double的精度问题就跟鬼一样,实在不明白同意义的式子有不一样的结果
}
return 0;
}
F
题意
求函数的解
思路
f(x)求导可知在[0,1]上单调递减。所有有唯一解的充要条件是f(0)>0 且 f(1)<0。利用单调性,可以用二分解决。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const double eps = 1e-8;//定义一个趋于0的数,即足够小的正数
int p,q,r,s,t,u;
double f(double x)
{
return exp(-x)*p+sin(x)*q+cos(x)*r+tan(x)*s+x*x*t+u;
//使用的数学函数均返回浮点数,所以结果最接近0的解就是所求解
}
int main()
{
while (scanf("%d%d%d%d%d%d",&p,&q,&r,&s,&t,&u)!=EOF)
{
if (f(0) < -eps || f(1) > eps)//单调递减函数没有唯一解的条件
{
cout<<"No solution"<<endl;
continue;
}
double l = 0;
double r = 1;
double ff;
double x;
for (int i=0; i<100; i++)//100次二分查找
{
x = (l+r)/2.0;
ff = f(x);
if (ff < -eps)//根据单调递减函数图像判断X是放大还是缩小
r = x;
else if (ff > eps)
l = x;
else
break;//若所取X带入函数结果趋于0,则为所求解
}
printf("%.4lf\n",x);
}
return 0;
}
G
题意
判断一组数是不是Jolly,即相邻数字之间差值的绝对值从1到n-1都有
思路
没有算法,直接简单模拟,数组a存放原始数据,数组b存放数组a相邻的元素的差值的绝对值,将b的值排一下序,看一下是不是所有的b[i]=i+1,所有的都符合输出Jolly else 输出Not Jolly
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=3007;
int a[maxn],b[maxn];
using namespace std;
int main()
{
int n,flag;
while(cin>>n)
{
for(int i=0; i<n; i++)
cin>>a[i];
for(int i=0; i<n-1; i++)
b[i]=abs(a[i]-a[i+1]);
sort(b,b+n-1);
flag=0;
for(int i=1; i<n; i++)
{
if(b[i-1]!=i)
{
flag=1;
break;
}
}
if(!flag)
cout<<"Jolly"<<endl;
else
cout<<"Not jolly"<<endl;
}
return 0;
}
H
题意
有N头牛叠罗汉,对于每头牛定义一个难受值,这个值等于在它上面的所有奶牛的体重减去它的力量。让你求一种排序方法使所有牛的难受值最小,题目让我们输出这个排序中最大的一头牛的难受值。
思路
难点在于贪心的选择,可以试想,如果在底部的牛它的体重和力量越大,那么其他在上面的牛的总体重就越小,再减去底下牛的力量,因为力量大,所得难受值就越小了,所以按照每头牛的体重+力量这个值进行排序。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=100007;
struct node
{
LL w;
LL s;
} cow[maxn];
bool cmp(node a,node b)
{
return a.s+a.w<b.s+b.w;
}
int main()
{
int n;
while(cin>>n)
{
for(int i=0; i<n; i++)
cin>>cow[i].w>>cow[i].s;
if(n==1)
{
cout<<-cow[0].s<<endl; //n==1时直接输出负的牛的力量
continue;
}
sort(cow,cow+n,cmp);
LL t=0,res=-999999;//初始化一个很小的数
for(int i=0; i<n; i++)
{
if(t-cow[i].s>res) res=t-cow[i].s; //找最大
t+=cow[i].w; //不断累积
}
cout<<res<<endl;
}
return 0;
}
I
题意
中文==人话,相信你们看得懂题
思路
动态规划中的回溯法,从倒数第二行开始更新,从底向上不断选择最优值,不断更新塔的数字,最终塔顶的数字就是最优值,更新方法可对着代码步骤在纸上模拟一下,回溯法主要是逆向思维,从底向上选择。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=107;
int main()
{
int k;
cin>>k;
while(k--)
{
int m;
cin>>m;
int a[maxn][maxn];
for(int i=0; i<m; i++)
{
for(int j=0; j<i+1; j++)
{
cin>>a[i][j];
}
}
for(int i=m-2; i>=0; i--)
{
for(int j=0; j<=i; j++)
{
if(a[i+1][j]>=a[i+1][j+1])
a[i][j]+=a[i+1][j];
else
a[i][j]+=a[i+1][j+1];
}
}
cout<<a[0][0]<<endl;
}
return 0;
}
J
题意
一排富有的村子,一排贫穷的村子,然后对应的村之间修路,要求不交叉,最多能修多少条。
思路
这题很难想到是求最大递增子序列,可以按照贫穷村子的序号从小到大排序,然后找富有村子序列的最长上升子序列就可以了,因为当贫穷村子按顺序排好依次修好与对应富村的路时,排在后面的贫穷村子只能选择比前面序号要大的富村,这样就能保证不相交,而且最大递增子序列的长度就是最优解。最长上升子序列的n×logn算法就是,来一个数,比序列末尾大就直接加入队尾,否则从队列中找到第一个比当前数大的,用当前数将其替换,最后队列的长度就是解。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=500007;
struct node
{
int s,e;
} a[maxn];
int len,n;
int dp[maxn];//记录最长上升子序列
int cmp(node a,node b)
{
return a.s<b.s;
}
void LIS()
{
memset(dp,0,sizeof(dp));
int l,r;
len=1;//初始最长上升子序列长度默认为1
dp[1]=a[1].e;
for (int i=2; i<=n; i++)
{
//二分查找dp中第一个比当前数还大的数,避免超时,未找到则添加到队尾
l=1,r=len;
while (l<=r)
{
int mid=(l+r)>>1;//位运算,向右一位相当于除以2
if (a[i].e>dp[mid])
l=mid+1;
else
r=mid-1;
}
dp[l]=a[i].e;
if (l>len)
len++;
}
}
int main()
{
int t=1;
while (scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
for (int i=1; i<=n; i++)//数组下标从1开始
cin>>a[i].s>>a[i].e;
sort(a+1,a+n+1,cmp);
LIS();
printf("Case %d:\n",t++);
if (len==1)//输出单词road单复数也是坑哦
printf("My king, at most %d road can be built.\n\n",len);
else
printf("My king, at most %d roads can be built.\n\n",len);
}
return 0;
}
K
题意
这个游戏可以由两个或两个以上的玩家玩。它由一个棋盘和一些棋子组成,所有的棋子都用一个正整数来标记。玩家从起点开始,最后必须跳到终点。在跳跃的过程中,玩家会访问路径中的棋子,但是每个人都必须从一个棋子跳到另一个绝对大的棋子。所有的玩家都不能倒退。一跳可以从一个棋子跳到下一个,也可以跨越多个棋子。注意,你的分数来自于你跳跃路径上的棋子值的总和。您的任务是根据给定的棋子列表输出最大值。
思路
题目一看就是求递增子序列的最大和,动态转化方程不理解的可以参考顶上的博客。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=2007;
LL a[maxn],b[maxn],dp[maxn];//虽然每个数字都在int范围内,但求和后可能会溢出,所以设为LL
//dp[i]表示序列到下标i为止的递增子序列最大和
int main()
{
int n;
while(cin>>n)
{
if(n==0)
break;
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(int i=0; i<n; i++)
cin>>a[i];
LL ans = -99999;//初始化一个很小的数求最大值
for(int i=0; i<n; i++)
{
dp[i] = a[i];
for(int j=0; j<i; j++)
{
if(a[j]<a[i])
dp[i] = max(dp[j]+a[i], dp[i]);//动态转化方程
}
ans = max(ans,dp[i]);
}
cout<<ans<<endl;
}
return 0;
}
L
题意
题目标题即所求,求最长公共子序列的长度。
思路
具体思想和思路解法参考顶上的博客,代码供参考。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1007;
int f[maxn][maxn];
char s1[maxn], s2[maxn];
int len1, len2;
int main()
{
while(scanf("%s %s", s1, s2) != EOF)
{
len1 = strlen(s1);
len2 = strlen(s2);
memset(f, 0, sizeof(f));//初始化
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(s1[i-1] == s2[j-1])
f[i][j] = f[i-1][j-1]+1;
else
f[i][j] = max(f[i-1][j], f[i][j-1]);
}
}
cout << f[len1][len2] << endl;
}
return 0;
}
M
题意
01背包问题模型,给定物品个数和背包体积,给出每个物品的价值和放进背包所要消耗的体积,对于每个物品只能选择要与不要,所以叫01背包,要求合理选择物品,在不超出背包体积下,使背包内物品的总价值最大。
思路
参考顶上博客对于背包问题的解法,详细易懂,小小菜鸡就不在大佬面前班门弄斧了。(优化后用一维数组的代码更加简单易懂,博客中也有提到,这里使用二维数组,掌握后更能很好地理解优化后的代码)
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1007;
struct bone
{
int value,cost;
};
bone x[maxn];
int dp[maxn][maxn];
int main()
{
int k;
cin>>k;
while(k--)
{
int n,v;
cin>>n>>v;
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
cin>>x[i].value;
for(int i=1; i<=n; i++)
cin>>x[i].cost;
for(int i=1; i<=n; i++)
{
for(int j=0; j<=v; j++)
{
if(j>=x[i].cost)
dp[i][j]=max(dp[i-1][j],dp[i-1][j-x[i].cost]+x[i].value);
else
dp[i][j]=dp[i-1][j];
}
}
cout<<dp[n][v]<<endl;
}
return 0;
}
N
题意
与上一道题类似,只不过多了物品的种类和每个种类对应的物品数。
思路
只是给物品分了类,同种类的物品属性是一样的,还是背包放物品的问题,在上一道题的基础上进行变换即可,这里是优化后用一维数组表示的代码。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=107;
struct rice
{
int value,weight,num;
};
int main()
{
int k;
cin>>k;
rice x[maxn];
int dp[maxn];
while(k--)
{
int money,kind;
cin>>money>>kind;
memset(dp,0,sizeof(dp));
for(int i=1; i<=kind; i++)
cin>>x[i].value>>x[i].weight>>x[i].num;
for(int i=1; i<=kind; i++)
{
for(int j=1; j<=x[i].num; j++)
{
for(int l=money; l>=x[i].value; l--)
{
dp[l]=max(dp[l],dp[l-x[i].value]+x[i].weight);
}
}
}
cout<<dp[money]<<endl;
}
return 0;
}~
O
自己掌握完全背包和多重背包,以及01背包二进制优化
推荐博客:1、https://blog.csdn.net/qq_38984851/article/details/81133840.
2、https://blog.csdn.net/qq_41286356/article/details/106882943?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.nonecase.
掌握了解后再自己解决本题。
P
解题思路很详细的博客链接: https://blog.csdn.net/liangbopirates/article/details/9632829.
Q
题意
研究人员有n种类型的砖块,每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi,yi,zi来表示。 同时,由于砖块是可以旋转的,每个砖块的3条边可以组成6种不同的长宽高。在构建塔时,当且仅当A砖块的长和宽都分别小于B砖块的长和宽时,A砖块才能放到B砖块的上面,因为必须留有一些空间让猴子来踩,
你的任务是编写一个程序,计算猴子们最高可以堆出的砖块们的高度。
思路
1.先列出所有长方体的情况,每种长方体有6种摆法。
2.将所有长方体按先长后宽由大到小进行排序,以便进行顺序堆叠。
3.然后j到i之间的长方体进行堆叠(遍历了所有可堆叠的情况),记录下最大的高度,
4.每i层之前的最大高度加上本层高度作为下次比较的高度,并记录下来。
5.输出所有堆叠高度里面最高的.
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=207;
struct node
{
int x,y,h;
} a[maxn];
int ant;
bool cmp(node a,node b)
{
//几种积木长宽高的各种情况进行排序,当长不同时,按长从大到小排列;相同时,按宽从大到小排列
if (a.x == b.x)
return a.y > b.y;
return a.x > b.x;
}
void PushUp(int t1,int t2,int t3)
{
//列出同种积木长宽高的各种情况,一种积木长宽高有6种情况
a[ant].h = t3;
a[ant].x = t1;
a[ant].y = t2;
ant++;
a[ant].h = t3;
a[ant].x = t2;
a[ant].y = t1;
ant++;
a[ant].h = t2;
a[ant].x = t1;
a[ant].y = t3;
ant++;
a[ant].h = t2;
a[ant].x = t3;
a[ant].y = t1;
ant++;
a[ant].h = t1;
a[ant].x = t2;
a[ant].y = t3;
ant++;
a[ant].h = t1;
a[ant].x = t3;
a[ant].y = t2;
ant++;
}
int main()
{
int n;
int ans;
int dp[maxn];
int Case = 1;
while (scanf ("%d",&n)!=EOF)
{
if(n==0)
break;
ant = 1;
for (int i = 1 ; i <= n ; i++)
{
int t1,t2,t3;
scanf ("%d %d %d",&t1,&t2,&t3);
PushUp(t1,t2,t3);
}
ant--;
printf ("Case %d: maximum height = ",Case++);
sort (a+1, a+1+ant, cmp);
ans = 0;
for (int i = 1 ; i <= ant ; i++)
{
dp[i] = a[i].h;
for (int j = i - 1 ; j >= 1 ; j--)
{
if (a[i].x < a[j].x && a[i].y < a[j].y)
dp[i] = max (dp[i], dp[j] + a[i].h);
}
ans = max (ans, dp[i]);
}
printf ("%d\n",ans);
}
return 0;
}
R
题意
求N的阶乘,很明显当N很大时,结果会溢出,会显示乱码。
思路
可将结果用数组表示,数组的长度就是结果的位数,数组元素的值就是对应结果每一位的数字,求出结果也只需要模拟我们平常在草稿纸上用竖式算乘法的过程。
代码
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=50007;
int main()
{
int n;
int a[maxn];
while(scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
a[0]=1;
int cnt=1;
for(int i=1; i<=n; i++)
{
int k=0;
for(int j=0; j<cnt; j++)
{
//模拟竖式乘法计算
int tmp=a[j]*i+k;
a[j]=tmp%10;
k=tmp/10;
}
//当最后一位乘完还有进位时,代表计算结果多出一位,那么数组长度增加
while(k)
{
a[cnt++]=k%10;
k/=10;
}
}
for(int i=cnt-1; i>=0; i--)
{
if(i==0)
printf("%d\n",a[i]);
else
printf("%d",a[i]);
}
}
return 0;
}