编程题
感悟:由于题目写的太水,反思.....
1.倒序打印三角形
我的通过代码:
总体思路是找到第一个打印的数与n的关系(first=n*(n+1)/2)。第一行最多有n个数
,之后n--,找一个数保存最大列,然后答案印完一行,列数就减一。
#include <stdio.h>
#define N 100
int main () {
int n,row,col,i,j,a[N][N];
scanf("%d",&row);
col=row;
for(i=1;i<=row;i++) {
n = col*(col+1)/2;
for(j=1;j<=col;j++) {
if(j==col) printf("%d\n",n);
else printf("%d ",n);
n--;
}
col--;
}
return 0;
}
缺点:虽然容易想到吧,但是执行时间太长....
这不,找到了个执行时间短一点的,注意列可以与行产生“关系”!代码如下:
#include <iostream>
using namespace std;
int main () {
int n,i,j,sum;
cin >> n;
sum = n*(n+1)/2; //第一个打印的数
for(i=0;i<n;i++) //控制行
{
for(j=n-i;j>0;j--) //j=n-i,就动态的把列数给减小了,简直不要太nice
{
cout << sum;
if(j>1) cout << " ";
sum--;
}
cout << endl;
}
return 0;
}
2.棋盘走法
题目描述:
图片往往令人浮想联翩....
答题思路:动态规划
先将第一行的值赋为1,因为只能向下或者向右,所以从(0,0)开始到第一行,
只能有一种走法。(每个数组里面的值代表着走法)右下角的格子的走法等于其
左边的走法加上其上边的走法。即: a[i][j]=a[i-1][j]+a[i][j-1];
代码如下:
#include <iostream>
#include <cstdio>
#define N 400
using namespace std;
int main () {
int a[N][N],i,j,n;
cin >> n;
for(i=0;i<n;i++) {
a[0][i]=1;
}
for(i=1;i<n;i++) { //注意i=1
for(j=i;j<n;j++) { //j=i
a[i][j]=a[i-1][j]+a[i][j-1];
}
}
cout << a[n-1][n-1];
return 0;
}
3.瓶盖换汽水
注意 :重要的是先理清一种情况下的最大可乐数,那个sum函数里面的while循环
要好好的理清楚,参数比较多,脑壳子不清醒的话就绕进去了.....
代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int n,x,y;
//本函数只解决一种情况下,即a瓶普通可乐,b瓶青柠可乐,最终能喝到的可乐数
int sum(int a,int b) { //普通可乐a瓶,青柠可乐b瓶
int ans=n; //刚开始买了 n瓶
int coke1,coke2;
while(a>=x || b>=y){
coke1 = a/x;
//该普通可乐a瓶的a个瓶盖最多能换coke1瓶青柠味的可乐
coke2 = b/y;
ans += coke1+coke2;
a = a%x + coke2;
//a%x是剩下未用的瓶盖,加上第一次换了之后的普通可乐(有coke2瓶)的瓶盖
b = b%y + coke1;
}
return ans;
}
int solve() {
cin >> n >> x >> y;
int ans = 0;
for(int i=0;i<=n;i++) {
ans = max(ans,sum(i,n-i));
//sum(i,n-i)即i瓶普通,n-i瓶青柠,用一个循环找到所有可能中的最大值
}
cout << ans << endl;
}
int main () {
int times;
cin >> times; //有times组测试
while(times--) {
solve();
}
return 0;
}
4.蛇形矩阵
这种题还用说,肯定是擅长的找规律题,但是我看一个真的看不出规律来。。。
考点:模拟
感想:自己没写出来也就算了,看别的题解,上来就是一个速读,哇,真恐怖...
先复制粘贴一波:
核心仍然在for循环里面,感觉十分巧妙的利用了x和y
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int mp[105][105];
int cnt = 0;
int main()
{
ios::sync_with_stdio(false);
int n = r;
//上三角
for(int i = 1;i <= n; i++){
if(i % 2){
for(int x = 1, y = i; x <= i && y >= 1; x++, y--){
mp[x][y] = ++cnt;
}
}else{
for(int y = 1, x = i; y <= i && x >= 1; y++, x--){
mp[x][y] = ++cnt;
}
}
}
for(int i = n-1;i >= 1; i--){
if(i % 2){
for(int x = n - i + 1, y = n; x <= n; x++, y--){
mp[x][y] = ++cnt;
}
}else{
for(int y = n - i + 1, x = n; y <= n; y++, x--){
mp[x][y] = ++cnt;
}
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cout<<mp[j][i];
if(j != n){
cout<<" ";
}
}
cout<<endl;
}
return 0;
}
接下来第二种上代码:
#include <iostream>
#include <cstdio>
using namespace std;
int a[200][200];
int main () {
int n,num=1,flag=0;
cin >> n;
//先打印上三角
for (int i=1;i<=n;i++) {
if(flag==0) {
for(int j=1;j<=i;j++) {
a[i-j+1][j] = num++;
}
flag = 1;
}
else {
for(int j=1;j<=i;j++) {
a[j][i-j+1] = num++;
}
flag = 0;
}
}
for(int i=n+1;i<2*n;i++) {
int t = 2*n-i;
if (flag==0) {
for (int j=i-n+1;j<i-n+1+t;j++){
a[i-j+1][j]=num++;
}
flag = 1;
}
else {
for (int j=i-n+1;j<i-n+1+t;j++){
a[j][i-j+1]=num++;
}
flag = 0;
}
}
for(int i=1;i<n;i++) {
for (int j=1;j<n;j++)
printf("%d ",a[i][j]);
printf("%d\n",a[i][n]);
}
for(int j=1;j<n;j++) {
printf("%d ",a[n][j]);
}
printf("%d",a[n][n]);
return 0;
}
我们注意到是以中间的对角线为分隔线开始打印,
还有一种解法(C语言),这个好理解:
#include <stdio.h>
int main () {
int n,N,i,j,k=0,a[100][100];
scanf("%d",&n);
N=1; //以1 开始打印
int m=2*(n-1); //最后一行行和列相加等于2*(n-1)
for(k=0;k<=m;k++) {
if(k%2==0 && k<n) { //k<n即左上三角
for(i=0;i<=k;i++,N++)
a[k-i][i]=N; //k+i + i = k,
}
else if (k%2==1 && k<n) {
for(i=0;i<=k;i++,N++)
a[i][k-i]=N;
}
else if (k%2==0 && k>=n) {
for(i=n-1;i>k-n;i--,N++)
a[i][k-i]=N;
}
else if (k%2==1 && k>=n) {
for(i=n-1; i>k-n; i--,N++)
a[k-i][i]=N;
}
}
for(i=0;i<n;i++) {
for(j=0;j<n;j++){
printf("%d",a[i][j]);
if(j<n-1) printf(" ");
}
printf("\n");
}
return 0;
}
5.传球游戏
动态规划,很显然我还不是很了解下面的代码是啥意思...待我学成归来在回顾这一题
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
ull dp[999][2];
int main()
{
ios::sync_with_stdio(false);
int n = r;
dp[1][0] = 3;
for(int i = 2; i <= n; i++){
dp[i][1] = dp[i-1][0];
dp[i][0] = dp[i-1][0] * 2 + dp[i-1][1] * 3;
}
cout<<dp[n][1];
return 0;
}
6.分糖果
思路:
我:刚开始想到的是分为两个数组,一个数组里面放输入的数,另一个放应该输
出的。先让第二个数组里面全为1,即保证每个人分到一个糖果,然后在遍历,如
果前面的数大于后面的,则相应的数组里面加一,但是只能保证一轮里面只有1和
2,能过简单的样例,没有考虑到还有会三个糖的,所以遍历一遍远远不够,然后
开始跑偏,写不出来了...时间截止了...
大佬:将前面一个的糖果和后面一个的糖果联系起来。
#include <bits/stdc++.h>
#pragma GCC optimize(3,"Ofast","inline")
#define re register
#define ll long long
#define ull unsigned long long
#define r read()
using namespace std;
//速读
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int s[10000];
int cnt[10000];
ll ans = 0;
int main()
{
ios::sync_with_stdio(false);
int n = r;
for(int i = 1; i <= n;i++){
s[i] = r; //每个人的评分
cnt[i] = 1; //每个人至少一个糖果
}
for(int i = 2; i <= n; i++){
if(s[i]-s[i-1]> 0){ //如果右边的比左边大,则右边的糖果比左边的糖果多一个
cnt[i] = cnt[i-1] + 1;
}
}
for(int i = n; i >= 2; i--){
//从右往左循环一次,如果左边比右边大,则左边比右边要多一个糖果
if(s[i]-s[i-1] < 0){
if(cnt[i] >= cnt[i-1]){
cnt[i-1] = cnt[i] + 1;
}
}
}
for(int i = 1;i <= n; i++){ //把所有糖果加起来
ans += cnt[i];
}
cout<<ans<<endl;
for(int i = 1; i <= n; i++){
cout<<cnt[i];
if(i != n){
cout<<" ";
}
}
return 0;
}
关于第二个for循环:
for example:输入5个人的评分为:1 4 7 2 1,
第一个for循环分到的结果为:1 2 3 1 1,但显然评分为2的那个boy原本要比
最后一个小伙子分到的多,但是由于他比左边的要小,所以并不能加糖果,于是
聪明的我,又从后面来了一次遍历,把boy的糖果给补上了,才能得到最终的结果。
笔试题
(还在反思ing)
网页题
写的心碎。。。