题目1:镜像序列(找规律)
一个序列的生成方式如下:
序列生成需要一个基础序列A,这个序列由n个不大于100的数字组成,同时给定镜像复制次数n。
然后对于A进行m次镜像复制,例如序列A={1,2,3}
则一次镜像复制后得到的序列是{1,2,3,3,2,1)
两次镜像复制得到的序列是B=(1,2,3,3,2,1,1,2,3,3,2,1)。
现在给出你生成一个序列所需要的参数,请你计算该序列的第k位是多少。 输人描述 输入第一行包含三个整数n,m,k,含义如题所示。
(1<=n<=100,1<=m<=60,1<=k<=1e18,部分数据k<10000)
输入第二行包含n个正整数,每个正整数都不大于100,表示基础序列A。 数字间有空格隔开 输出仅包含一个正整数,即序列第k位的数字。
input:
3 3 10
1 2 3
# 输入
n, m, k = list(map(int, input().split()))
a = list(map(int, input().split()))
# 复杂度极高的解法:
# 用for循环生成
k = k - 1
for i in range(m):
i += 1
a = a + list(reversed(a)) #或者 a = a + a[::-1] 切片截取
print(a[k])
#用除余方法:
a = a + a[::-1]
k = k / (2*n) - 1
print(a[k])
题目2:加减数组元素使乘积为7(贪心或动态规划)
给定n个整数a1, a2, a3…an。每次操作可以选择其中一个数,并将这个数加上1或者减去1。
小红非常喜欢7这个数,他想知道至少需要多少次操作可以使这n个数的乘积为7?
输入描述
第一行输入一个正整数n,表示整数的个数。
第二行输入n个整数a1, a2, a3…an,其中ai表示第i个数。
输出描述
输出一个整数,表示将所有数的乘积变为7最少需要的操作次数。
input:
5
-6 0 2 -2 3
output:
6
# 贪心算法
# 一个元素 7
# 两个元素 7和1 ++ --
# 三个元素 7 1 1 +++ +--
# 贪心方法:先找最接近7或者-7的;再将其他值变为-1或1
# 输入
n = int(input())
A = list(map(int,input().split))
count = 0
neg = 0
if n > 1:
# map函数 map(function,iterable) iterable一个或者多个序列
# def f(x):
# return x*x
# print(list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])))
# str.split(str="", num=string.count(str)) num表示分隔次数,遇到num次分隔,后面的不管
# 寻找list里距离7或者-7最近的值,取绝对值法对原来的list进行取值
B = max(A, key = abs) #返回取绝对值后最大的值对应的原值
# max函数里用key关键词引用一个函数,先对该list调用函数再取max,并且返回的是原来list的值
# 字典里用key = a.get 表示a.get(item) 输出最大的值(item)对应的键(key)。否则在字典里的key中选最大值。
A.remove(B) #将该数值从列表中去除
if B>=0:
count += abs(B-7)
else:
count += abs(B+7)
# 负数要记录
neg += 1
# 对其他数取-1和1值,考虑如果有0,则可以不需要在意neg
M = min(A, key = abs)
# 将所有值调整为1或-1
for i in A:
# 把小于0的都调整为-1
if i < 0 :
count += abs(i + 1)
neg += 1
# 把大于等于0的都调整为1
else:
count += abs(i - 1)
# 如果有0,不需要考虑neg,只要变为1或-1都可以
if M != 0 && (neg / 2) != 0:
count += 2
else:
count = abs(7-B)
print(count)
//动态规划解法
public class solution {
public void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
// 对每个元素都计算与7 -7 1 -1的距离,从0开始
long dp7 = Math.abs(a[0] - 7); //与7的距离
long dp_7 = Math.abs(a[0] + 7); //与-7的距离
long dp1 = Math.abs(a[0] - 1); //与1的距离
long dp_1 = Math.abs(a[0] + 1); //与-1的距离
// 遍历每个位置
for (int i = 1; i < n; i++) {
int v = a[i]; // 元素1
// 新加入的元素取什么值
// 整体结果为-7
long newDp_7 =
Math.min(
Math.min(
dp_7 + Math.abs(v - 1), //本次取1 原来取-7 得到-7
dp_1 + Math.abs(v - 7) //本次取7 原来取-1 得到-7
),
Math.min(
dp1 + Math.abs(v + 7), //本次取-7 原来取1 得到-7
dp7 + Math.abs(v + 1)
)
);
// 整体结果为7
long newDp7 =
Math.min(
Math.min(
dp_7 + Math.abs(v + 1),
dp_1 + Math.abs(v + 7)
),
Math.min(
dp1 + Math.abs(v - 7),
dp7 + Math.abs(v - 1)
)
);
// 整体结果为-1
long newDp_1 =
Math.min(
dp_1 + Math.abs(v - 1),
dp1 + Math.abs(v + 1)
);
// 整体结果为1
long newDp1 =
Math.min(
dp_1 + Math.abs(v + 1),
dp1 + Math.abs(v - 1)
);
dp_7 = newDp_7;
dp_1 = newDp_1;
dp1 = newDp1;
dp7 = newDp7;
}
System.out.println(dp7);
}
}
题目3:最小过路费(图)
小明的旅途中需要经过一个国家。这个国家有n个城市,编号为1到n。小明会从1号城市进入,
目标是从n号城市出去(即要从1号城市到达n号城市)。有m条双向道路连接这n个城市,每条道路的长度都是1,并且都有一个过路费(是[1,100000]之间的整数)。
当小明在一号城市时他可以预先花费X的费用办一张特权卡,他可以获得所有过路费不超过X的道路的通行权(而其他道路无法通过)。
小明一天最多只能走k长度的路,他想知道如果他想在一天之内从1号城市到n号城市,他最少需要花费多少来办特权卡
即求X的最小值?
第一行是3个整数n,m,k,分别表示城市数,道路数和小明一天最多能走的长度
第二行m个整数,分别为u1, u2…um,分别表示第i条道路的一个端点。
第三行m个整数,分别为v1, v2…vm,分别表示第i条道路的另一个端点。
第四行m个整数,分别为w1, w2…wm,分别表示第条道路的过路费
数字间两两有空格隔开。数据保证一定存在解
输出描述
一行一个整数,表示X的最小值
input:
5 6 3
1 1 2 3 3 4
2 5 3 4 5 5
1 3 1 2 1 1
output:
1
# 读入图
n, m, k = list(map(int, input().split()))
u = list(map(int, input().split()))
v = list(map(int, input().split()))
w = list(map(int, input().split()))
# 用字典构造图,用defaultdict构建邻接表
from clollections import defaultdict
g = defaultdict(dict) # 内置一个dict
# 图的构造方法,可以用边和点的关系,用权重标识,否则为0
for i in range(m):
g[u[i]][v[i]] = w[i] # g[1][2] = 1,g[1][5] = 3,g[2][3] = 1
g[v[i]][u[i]] = w[i]
# 结果:
# g[1] = {2:1,5:3}
# g[5] = {1:3,3:1,4:1}
# 遍历法 记录路径,如果路径超过k,就跳过,广度优先搜索法,需要考虑visited
def check(y):
q = deque([1,0]) # 当前点为1,当前路径为0
visited = [False] * (n+1) # 已访问过就为true 也可以用set实现 visited = set() xx in visited
visited[1] = True
while q:
cnt,step = q.popleft()
if cnt == n:
return True
for nxt , v in g[cnt].items(): # 取该点的邻居及其权重
# 需要满足权重小于等于检查的值y 且 当前的路径加上1还能小于等于k 且 未参观该路径
if v <= y and step + 1 <= k and not visited[nxt]:
# 把该元素放入q中,进入下一次遍历
q.append([nxt,step+1])
visited[nxt] = True
return false
#用二分法实现寻找最小值
l = 1
r = max(w)
while l < r:
mid = l+r >> 1
if check(mid): # 说明mid可以通过,取左边
r = mid
else :
l = mid + 1
print(r)
同样的实现方法用java写一遍
class Solution{
private static final int N = 100010, M = 400010;
private static Queue<int[]> q = new ArrayDeque<>(N);
private static int n,m,k;
private static int[] u = new int[M],v = new int[M],w = new int[M];
private static int[][] edge;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
sc1 = sc.nextLine().split();
int n = Integer.parseInt(sc1[0]);
int m = Integer.parseInt(sc1[1]);
int k = Integer.parseInt(sc1[2]);
edge = new int[n+1][n+1];
// 存储图
sc2 = sc.nextLine().split();
sc3 = sc.nextLine().split();
sc4 = sc.nextLine().split();
maxW = Integer.parseInt(sc4[0]);
for(int j = 0; j < m; j++){
// 初始化图为邻居矩阵存储权值
edge[Integer.parseInt(sc2[j])][Integer.parseInt(sc3[j])] = Integer.parseInt(sc4[j]);
if (maxW < Integer.parseInt(sc4[j])){
maxW = Integer.parseInt(sc4[j]);
}
}
// 用二分法找最小值,如果mid不能通过,则在右侧,否则在左侧
int l = 1,r = maxW;
// 当mid不能通过时,选右侧
while(l < r){
int mid = (l+r)/2; // 用>>符号 l + r >> 1 运算更快
if(!bfs(mid)){
l = mid + 1;
}
else{
r = mid;
}
}
System.out.print(r);
}
// 判断用x的费用是否通路
public static boolean bfs(int y){
// 重新寻找通路
q.clear();
// 添加初始点1 和 初始路径距离0
q.add(new int[] {1,0});
HashSet<int> s = new HashSet<int>();
while (!q.isEmpty()){
int[] cur = q.poll();
int u = cur[0]; // 当前点
int step = cur[1];
s.add(u);
if (u == n): return true; // 若当前点为n则返回可以,否则遍历
for(int i = 1;i < n+1;i++){
if (edge[u][i] is null) continue;
if (i in s) continue;
if (edge[u][i] > y || step + 1 > k) continue;
else {
q.add(new int[]{i,step + 1});
s.add(i);
}
}
}
return false;
}
}