笔试题

题目1:二维数组(N*N),沿对角线方向,从右上角打印到左下角: 


  1. 1 2 3 4 }  
  2. 5 6 7 8 }  
  3. 9 10 11 12 }  
  4. {13 14 15 16 }  
  1. 4  
  2. 3 8  
  3. 2 7 12  
  4. 1 6 11 16  
  5. 5 10 15  
  6. 9 14  
  7. 13  


public class Main {

private static final int[][] DATA = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};  

public static void main(String[] args) {
int n = 4;
int i_data = 0;
int j_data = n-1;
while(i_data != n) {
for(int i=i_data,j=j_data;i<=n-1&&j<=n-1;i++,j++) 
System.out.print(DATA[i][j]+" ");
System.out.println();
if(j_data>0)
j_data--;
else
i_data++;
}
}

}



题目2:在一个桌子上放了若干个数值不等的红包,围成一个圈,现在让你选取若干个红包,要求相邻的两个红包不能同时选取,编程求出选取红包所得


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <math.h>


using namespace std;
const int MAXN = 22;
int arr[MAXN];
int n;


int newMethod(int start,int end,int signal){

int temp1=0,temp2=0;

if(start - end > 0)

return 0;

if(start-end == 0)

return  arr[start];

if(signal == 0){

temp1 = newMethod(start+2,end-1,1)+arr[start];

temp2 = newMethod(start+1,end,1);

}

else{

temp1 = newMethod(start+2,end,1)+arr[start];

temp2 = newMethod(start+1,end,1);

}

if(temp1>temp2)

return temp1;

else

return temp2;

}


int main()
{

    int T;

    cin>>T;

    while(T--)

    {

        n = 0;

        cin>>arr[n++];

        while(cin.get() == ',')

        cin>>arr[n++];

  int newMax = newMethod(0,n-1,0);

        printf("%d\n", newMax);

    }

    return 0;

}


动态规划解决该问题:

从某个红包按顺时针依次选取,则每个位置都有两种状态,选取和不选取,最终要使利益最大化,可以用动态规划来解决。在动态规划中,每一步的选择都是前面所有步骤的总结,每一步选择最优从而使最终方案最优。DP算法的这种本质决定了问题必须是线性结构,但本问题是环状结构,第一个红包(指逻辑上的第一个,环上的任何一个红包都可以作为第一个)的状态不仅影响第二个红包的状态,还影响最后一个红包的状态,所以首先要将环状结构转化为线性结构。转化方法:将所有选取方案分为两类,第一类是选取第一个红包的所有方案,第二类是不选取第一个红包的所有方案。对于第一类,选取第一个红包,从而第二个红包和最后一个红包都不能选取,剩余红包的状态不确定;对于第二类,不选取第一个红包,那么剩下的红包状态都不确定。将环状结构转化为线性结构可以使问题简化,逻辑更加清晰,顺序选取的过程中,每个红包的状态只取决与它前面一个红包,从而可以使用DP来求解。

第二步是分别对两类中不确定的红包运用动态规划。若某个位置的红包选取,那么其后一位置的红包不能选取;若某一位置的红包未选取,其后一位置的红包可以选取,也可以不选取。DP转移方程:

    dp[i+1][0]=max(dp[i][0],dp[i][1])

    dp[i+1][1]=dp[i][0]

其中i表示红包的索引,第二维中的0表示不取红包i,1表示选取红包i,也就是说第二维用来表示红包的两种状态;而dp[i][0]表示从红包0到红包i中选取红包,并且不选红包i,获得的红包最大值;dp[i][1]表示从红包0到红包i中选取红包,并且选取红包i,所获得的红包最大值。

算法时间复杂度为O(n),源代码:

[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <vector>  
  3. #include <algorithm>  
  4. using namespace std;  
  5.   
  6. vector<int> Money;  
  7.   
  8. int Choose(int begin, int end)  
  9. {  
  10.     if (end < begin) return 0;  
  11.     int dp[2], temp;  
  12.     dp[0] = dp[1] = 0;  
  13.     for (int i = begin; i <= end; i++)  
  14.     {  
  15.         temp = dp[0];  
  16.         dp[0] = max(dp[0], dp[1]);  
  17.         dp[1] = temp + Money[i];  
  18.     }  
  19.     return max(dp[0], dp[1]);  
  20. }  
  21.   
  22. int main()  
  23. {  
  24.     int T, n, val, ans;  
  25.     cin >> T;  
  26.     while (T--)  
  27.     {  
  28.         cin >> val;  
  29.         Money.push_back(val);  
  30.         while (cin.get() == ','){ cin >> val; Money.push_back(val); }  
  31.         /*for (int item : Money) cout << item << " "; 
  32.         cout << endl;*/  
  33.         n = Money.size();  
  34.         //第一类,选取红包0,然后对红包2到红包n-2进行DP  
  35.         ans = Money[0] + Choose(2, n - 2);  
  36.         //第二类,不选取红包0,然后对红包1到红包n-1进行DP  
  37.         ans = max(ans, Choose(1, n - 1));  
  38.         cout << ans << endl;  
  39.         Money.clear();  
  40.     }  
  41.       
  42.     return 0;  
  43. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值