第二批一共四道编程题,2道dp一道暴力搜索,一道田忌赛马,虽然有两道是经典题,但本菜鸡还是扛不住,宇宙条这难度还是让人服气的,另外面经就不写了,凉面写起来不舒服…
赤裸裸的田忌赛马,有兴趣的话可以去网上搜一搜hdu,没什么变动。
有两队人,输入n,表示每队有n个人,接着输入两行,每行n个数字,每个数字代表这个队员的速度。两队进行赛跑,赢一局,加一分,输一局,减一分,平局,不加不减,问你怎么跑第一队积分最高。
思路:
对两队人按照从快到慢都进行排序,之后从慢马开始比:
如果a队跑的慢的比b队跑得慢的快,那么直接加一分,继续比
如果a队跑的慢的比b队跑的慢的慢,那么我们实际操作时让a队跑的慢的跟b队跑的最快的比,此时减一分
如果两队的跑的慢的一样快,那么此时先比较两队跑的快的,a队跑的快的如果比b队跑得快的还要快,那么加一分,反之减一分,其余情况为平局,不加不减。
//
// toutiao1.cpp
// Algorithm
//
// Created by huangyi on 2019/7/7.
// Copyright © 2019 Leetcode. All rights reserved.
//
#include
#include
#include
using namespace std;
const int maxn = 2020;
int a[maxn], b[maxn];
bool cmp(int a, int b) {
return a > b;
}
int main()
{
int n, len1, len2;
int res = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d %d", &a[i], &b[i]);
}
//将两队马从快到慢排序
sort(a, a + n, cmp);
sort(b, b + n, cmp);
//最慢的马的位置
len1 = len2 = n - 1;
int i = 0, j = 0;
while(i <= len1 && j <= len2) {
//a队慢马 > b队慢马,加一分
if(a[len1] > b[len2]) {
res++;
len1--;
len2--;
} else if(a[len1] < b[len2]) {
res--;//我们让j++,len1--就是让a队的慢马跟b队的快马比
j++;
len1--;
} else {
if(i < len1) {
if(a[i] <= b[j]) {
//a队的快马不能赢
if(a[len1] < b[j]) {
res--;
}
len1--;
j++;
} else {
//a队的快马赢了
res++;
i++;
j++;
}
} else {
//平局
len1--;
len2--;
}
}
}
printf("%d\n", res);
return 0;
}
输入n,表示一共有n块石头,之后输入n个数,每个数代表当前石头的积分。现在有两队人,a队和b队。假设a队先开始捡石头,第一次可以捡1到2块,之后b队捡石头,b队可以捡一队的两倍范围,也就是b队可以捡2到4块,一直轮流下去。问你怎么减石头,a队可以得到最高的积分,输出该积分。
输入样例:
5
2 7 9 4 3
输出样例:
9
#include
using namespace std;
int n,a[2010];
int stoneGameII(vector<int>& piles) {
int len = piles.size();
vector<vector<int> > dp(len, vector<int>(len, 0));
vector<int> sum(len, 0);
sum.back() = piles.back();
//逆序部分和
for(int i = len-2; i >= 0; i--) {
sum[i] = sum[i+1] + piles[i];
}
//逆序查找,dp[i][j]表示当前在i位置,m = j - 1 可以获得的最大数
for(int i = len-1; i >= 0; i--) {
//m的范围为1到len,都遍历一遍
for(int j = 0; j < len; j++) {
int m = j + 1;
//剩下的时候可以一次性拿完
if(2*m >= len-i) {
dp[i][j] = sum[i];
} else {
//剩下的石头一次性拿不完,取最大的
for(int k = 1; k <= 2*m; k++) {
dp[i][j] = max(dp[i][j], sum[i]-dp[i+k][max(k,m)-1]);
}
}
}
}
return dp[0][0];
}
int main() {
scanf("%d", &n);
vector<int> nums;
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
nums.push_back(a[i]);
}
int res = stoneGameII(nums);
printf("%d\n", res);
return 0;
}
//
// toutiao2.cpp
// Algorithm
//
// Created by huangyi on 2019/7/7.
// Copyright © 2019 Leetcode. All rights reserved.
//
#include
using namespace std;
int n,a[2010],b[2010],c[2010],dp[2010][2010];
int main(){
scanf( "%d" , &n);
for( int i=1 ; i<=n ; i++ ){
scanf( "%d" , &a[i] );
}
b[n] = a[n];
for( int i=n-1 ; i>=1 ; i-- ){
b[i] = a[i]+b[i+1];
}
for( int i=1 ; i<=n ; i++ ){
dp[n][i] = a[n];
}
for( int i=n-1 ; i>=1 ; i-- ){
for( int k=1 ; i+k<=n ; k++ ){
c[k] = b[i]-dp[i+k][k];
}
for( int k=2 ; i+k<=n ; k++ ){
c[k] = max( c[k] , c[k-1] );
}
for( int j=1 ; j<=n ; j++ ){
int k = min(j*2,n-i);
dp[i][j] = c[k];
if( i+j+j>n )
dp[i][j] = b[i];
}
}
printf( "%d\n" , dp[1][1] );
return 0;
}
输入n和m,表示一共有n个人,之后一行输入n个数,分别表示每个人的身高,现在要求这些人围成一圈,要求是相邻的两个人身高不能超过m,问你一共有几种方案。
一开始没什么想法,用了两个if竟然也过了好几个样例…后来看了下,n个人的范围很小,不超过10。可以猜想这题应该是个暴力搜索。不过代码最后没有提交测试过,不知道对不对…
//
// toutiao3.cpp
// Algorithm
//
// Created by huangyi on 2019/7/7.
// Copyright © 2019 Leetcode. All rights reserved.
//
#include
using namespace std;
int n,m,ans,a[15],b[15],v[15];
void dfs( int idx ){
if( idx == n ){
if( abs(b[0] - b[n-1]) <= m ) ans++;
return;
}
for( int i = 0; i < n; i++ ){
if( v[i] ) continue;
if( abs(a[i] - b[idx - 1]) <= m ){
v[i] = 1;
b[idx] = a[i];
dfs(idx + 1);
v[i] = 0;
}
}
}
int main(){
scanf( "%d%d" , &n , &m );
for( int i=0 ; i<n ; i++ ){
scanf( "%d" , &a[i] );
}
if( n==1 ){
printf( "1\n" );
}else if( n==2&&abs( a[0]-a[1] )<=m ){
printf( "1\n" );
}else{
for( int i = 0; i < n; i++ ){
v[i] = 0;
}
ans = 0;
for( int i=0 ; i<n ; i++ ){
b[0] = a[i];
v[i] = 1;
dfs( 1 );
}
printf( "%d\n" , ans );
}
return 0;
}
输入n和m,代表背包上限和物品个数,输入w数组和c数组,分别代表每个物品的消耗和积分,问你怎么取物品放到背包里,积分能够最大。
//
// toutiao4.cpp
// Algorithm
//
// Created by huangyi on 2019/7/7.
// Copyright © 2019 Leetcode. All rights reserved.
//
#include
#include
using namespace std;
const int maxn = 100;
const int maxv = 2010;
//w[]消耗数组,c[]积分数组,dp[][]
//令dp[i][j]表示前i件物品(1<=i<=n,0<=j<=n)恰好装入容量为j的背包中所能获得的最大价值
int w[maxn],c[maxn],dp[maxn][maxv];
int main()
{
int n,m;
//n为背包上限,m为物品个数
scanf("%d%d",&n, &m);
for(int i = 0;i < m;i++){
scanf("%d %d",&w[i], &c[i]);
}
for(int i = 1; i <= m; i++){
for(int j = w[i]; j <= n; j++){
dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
}
}
printf("%d\n",dp[m][n]);
return 0;
}
思路:可以利用Condition的await和signal方法来等待和唤醒线程
package thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FirstThreadTest {
public static void main(String[] args) {
final AlternateDemo ad = new AlternateDemo();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ad.loopA();
}
}
}, "a").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ad.loopB();
}
}
}, "l").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
ad.loopC();
//System.out.println("-----------------------------------");
}
}
}, "i").start();
}
}
class AlternateDemo {
private int number = 1; //当前正在执行线程的标记
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void loopA() {
lock.lock();
try {
//1. 判断
if (number != 1) {
condition1.await();
}
//2. 打印
System.out.print(Thread.currentThread().getName());
//3. 唤醒
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void loopB() {
lock.lock();
try {
//1. 判断
if (number != 2) {
condition2.await();
}
//2. 打印
System.out.print(Thread.currentThread().getName());
//3. 唤醒
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void loopC() {
lock.lock();
try {
//1. 判断
if (number != 3) {
condition3.await();
}
//2. 打印
System.out.print(Thread.currentThread().getName());
//3. 唤醒
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
有一个字符串它的构成是词+空格的组合,如“北京 杭州 杭州 北京”, 要求输入一个匹配模式(简单的以字符来写), 比如 aabb, 来判断该字符串是否符合该模式, 举个例子:
pattern = “abba”, str=“北京 杭州 杭州 北京” 返回 true
pattern = “aabb”, str=“北京 杭州 杭州 北京” 返回 false
pattern = “baab”, str=“北京 杭州 杭州 北京” 返回 true
思路,建立两个map,把两个字符数组和单词数组分别映射到map里去,键分别为字符和单词,值都是int。同时建立两个int数组,分别用来存放相应map映射的值。
最后只需要比较两个数组是否相等即可
//
// Ali2.cpp
// Algorithm
//
// Created by huangyi on 2019/7/12.
// Copyright © 2019 Leetcode. All rights reserved.
//
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull base = 1000003;
const int mod = 1e9+7;
string pattern,str;
map<char,int> mp1;
map<string,int> mp2;
int num1,num2;
vector<int>a;
vector<int>b;
bool same(){
if( a.size()!=b.size() ){
return false;
}
for( int i=0 ; i<a.size() ; i++ ){
if( a[i]!=b[i] ){
return false;
}
}
return true;
}
int main(){
cin>>pattern;
getchar();
getline( cin , str );
for( int i=0 ; i<pattern.length() ; i++ ){
if( !mp1.count(pattern[i]) ){
mp1[pattern[i]] = ++num1;
}
a.push_back(mp1[pattern[i]]);
}
string part = "";
for( int i=0 ; i<=str.length() ; i++ ){
if( i==str.length()||str[i]==' ' ){
if( !mp2.count(part) ){
mp2[part] = ++num2;
}
b.push_back(mp2[part]);
part = "";
}else{
part = part+str[i];
}
}
if( same() ) {
printf( "true\n" );
} else {
printf( "false\n" );
}
return 0;
}