第一题
题目描述:给定一个数组,求这个数组最多能被分解成长度为多少的素数数组
输入格式:n数组长度, 然后连续输入n个数作为数组的值
输出格式:最长素数数组长度
示例:
输入:
3
1 1 1
输出:
0
分析:1本身不是素数,所以他的分解为0个
输入:
3
3 5 7
输出:
6
分析:3不用分解,5={2,3},7={2,2,3},总数是6个
我自己的C++实现:
/*
我感觉只要全按照2来分解不就好了? 整数x的分解的素数个数就是 x>>=2
但是我的解法只AC了不到60%,不知道错在哪了
*/
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
int result = 0;
for (int i=0; i<n; i++){
int m;
cin >> m;
m >>= 1; //右移一位,相当于除以2再取整
result += m;
}
cout << result << endl;
return 0;
}
第二题
题目描述:排队买火车票,每个人可以给自己买(时间消耗a[i]
),或者连同后面的人一起买(时间消耗b[i]
),最后一个人只能给自己买,求总体的最短时间
最后的输出格式有要求08:00:40 am这种的,注意12点是am哈哈。
输入样例:
2 // 测试次数T
2 // 人数n
20 45 //a数组
40 //b数组
1
8
输出结果:
08:00:40 am
08:00:08 am
我自己的C++实现:
/*
用动态规划来求解就可以了
状态转移方程:
f[j] = min(f[j-1]+a[j], f[j-2]+b[j])
AC100%
*/
#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
using namespace std;
const int MAXL = 2010;
int a[MAXL],b[MAXL];
int f[MAXL];
int main(){
int T;
cin >> T;
for (int i=0; i<T; i++){
int hour = 8, minute = 0, second = 0;
int n;
int result=0;
cin >> n;
for (int j=1; j<=n; j++) cin>>a[j];
for (int j=1; j<=(n-1); j++) cin>>b[j];
if (n==1) result = a[1];
else{
f[0] = 0;
f[1] = a[1];
for (int j=2; j<=n; j++){
f[j] = min(f[j-1]+a[j], f[j-2]+b[j-1]);
}
result = f[n];
}
hour = (hour + result/3600)%24;
minute = (minute + result/60)%60;
second = (second + result % 60);
if (hour <= 12)
printf("%02d:%02d:%02d am\n",hour,minute,second);
else
printf("%02d:%02d:%02d pm\n",hour,minute,second);
}
return 0;
}
第三题
题目描述:给定一个数组,问至少要丢掉总共多少价值的数,才能将这个数组均等划分给两个人。
我自己的C++实现:
/* 暂时还没有思路,现在感觉有点像更加复杂一点的背包问题,但是状态转移方程并没有想出来 */
第四题
题目描述:求两个教授互相欣赏的对数。
输入:
n,m //博士人数,连接数
m 行 // 每一行代表从那个点出发到另外一个点的连接
输出:
result //互相欣赏的博士对数
输入样例:
8 9
1 3
2 1
3 2
3 4
4 5
5 6
6 7
7 8
8 5
输出结果:
9
分析:
用tarjan算法求有向图最大强连通分量
记录每个强连通分量的个数
然后对每个数求组合 C(n,2) = n(n-1)/2
我自己的C++实现:
/*
用tarjan算法求有向图最大强连通分量
记录每个强连通分量的个数
然后对每个数求组合 C(n,2) = n(n-1)/2
*/
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
using namespace std;
const int MAXN = 10010;
int dfn[MAXN], low[MAXN]; //dfn[i]记录被访问的时间节点, low[i]记录该节点能访问到的最早出现的节点序号
int time, group_index;
int subnum[MAXN], visited[MAXN];
stack<int> s;
vector<int> graph[MAXN]; // 邻接表存储
void Tarjan(int u){
time ++;
//初始化
dfn[u] = time;
low[u] = time;
visited[u] = 1;
s.push(u);
for (int i=0; i<graph[u].size(); i++){
int v = graph[u][i];
if (!dfn[v]){
Tarjan(v);
low[u] = min(low[v], low[u]);
}
else if (visited[v] == 1){
low[u] = min(low[v], low[u]);
}
}
// 判断是否为根节点,若是则找到了一个新的强连通分量
if (dfn[u] == low[u]){
int v;
group_index ++;
do{
v = s.top();
subnum[group_index] += 1; //记数
visited[v] = 0;
s.pop();
}while(v!=u);
}
}
int main(){
int n, m;
cin >> n >> m;
for (int i=0; i<m; i++){
int x, y;
cin >> x >>y;
graph[x].push_back(y);
}
for (int i=1; i<=n; i++){
if (!dfn[i]){
Tarjan(i);
}
}
int result = 0;
for (int i=1; i<=group_index; i++){
int t = subnum[i];
result += t*(t-1)/2; // 对每个数求组合 C(n,2) = n(n-1)/2
}
cout << result << endl;
return 0;
}