@TOC
problem1 几何严格单调递增数组
问题
给定两个数组nums1, nums2, 其中nums1几何严格单调递增,判断能否从nums2中找一个数替换掉nums1中的一个数,使得nums1严格单调递增。如果可以的话,求出可用于替换的nums2中的最大数,否则输出"NO"。(注:几乎严格单调递增指的是除了仅有的一个位置以外,其余所有位置均是严格单调递增的)
分析
几乎严格单调递增数组可以分为两段,两段分别严格单调递增。可以先找出不严格单调递增的位置pivot,则只能通过修改nums1[pivot]或者nums1[pivot-1]即可使其严格单调递增
代码
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<map>
using namespace std;
void getAns(vector<int> &nums1, vector<int> &nums2){
//step1 寻找pivot
int n = nums1.size();
int pivot = -1;
for(int i=1; i<n; i++){
if(nums1[i]<=nums1[i-1]){
pivot = i;
break;
}
}
// 做法
sort(nums2.begin(), nums2.end()); //预排序,方便调用二分搜索,虽然复杂度高了,但代码简单点
// 如果修改nums1[pivot]
pair<int,int> ans(-1,-1);
if(pivot+1>=nums1.size() || nums1[pivot+1]>nums1[pivot-1]){
auto ite1 = upper_bound(nums2.begin(), nums2.end(), nums1[pivot-1]);
int end = 0x7fffffff;
if(pivot+1<nums1.size()) end = min(end, nums1[pivot+1]);
auto ite2 = lower_bound(nums2.begin(), nums2.end(), end);
if(ite2-ite1!=0){
ite2--;
ans = make_pair(pivot, *ite2);
cout<<*ite2<<endl;
}
}
// 如果修改nums1[pivot-1]
if(pivot-2<0 || nums1[pivot-2]<nums1[pivot]){
int start = 0x80000000;
if(pivot-2>=0) start = max(start, nums1[pivot-2]);
auto ite1 = upper_bound(nums2.begin(), nums2.end(), start);
auto ite2 = lower_bound(nums2.begin(), nums2.end(), nums1[pivot]);
if(ite2-ite1!=0){
ite2--;
if((*ite2)>ans.second){
ans.first = pivot-1;
ans.second = *ite2;
}
}
}
if(ans.first==-1) cout<<"NO"<<endl;
else{
nums1[ans.first] = ans.second;
for(auto val : nums1) cout<<val<<' ';
cout<<endl;
}
}
int main(){
/* 测试样例
* inpu
* 1 3 7 4 10
* 2 1 5 8 9
* output:
* 1 3 7 9 10
*/
string line;
getline(cin, line);
istringstream strin(line);
int tmp;
vector<int> nums1;
while(strin>>tmp) nums1.push_back(tmp);
strin.clear();
getline(cin, line);
strin.str(line);
vector<int> nums2;
while(strin>>tmp) nums2.push_back(tmp);
getAns(nums1, nums2);
return 0;
}problem2 字符串数组组环
问题
给定一个字符串数组,问能否通过调整这些字符串数组中元素的位置,使得其可以围城一个环,如果可以输出true,否则输出false。注:相邻两个字符串的邻接字母要相同
分析
step1 可以把原问题转化为图,如果两个字符串可以紧邻,说明他们之间存在这边。
step2 遍历图,是否可以存在一种遍历方式,经过遍历后,第一个字符串的第一个元素与最后一个字符串的最后一个元素相同,如果可以则存在环,否则不存在。
遍历图可以考虑dfs搜索,同时由于是要看是否有环,所以任意一个字符串均可以作为遍历的第一个元素,不妨以字符串数组中的一个元素作为开始
结果:只通过了95%,但是听讨论区的意见,好像该方法是对的,是测试样例的问题
代码
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<map>
using namespace std;
bool dfs(char start, char cur, vector<bool> &flag, vector<string> &nums, map<char, vector<int>> &charMap, int k){
if(k==0){
return cur==start;
}
for(auto val : charMap[cur]){
if(flag[val]==false){
flag[val] = true;
if(dfs(start, *nums[val].rbegin(), flag, nums, charMap, k-1)) return true;
flag[val] = false;
}
}
return false;
}
int main(){
/* 测试样例
* Input: CAT TIGER RPC
* Output: true
*/
string line;
getline(cin, line);
istringstream strin(line);
vector<string> nums;
map<char, vector<int>> charMap;
string tmp;
while(strin>>tmp){
nums.push_back(tmp);
charMap[tmp[0]].push_back(nums.size()-1);
}
vector<bool> flag(nums.size(), false);
flag[0] = true;
bool ans = dfs(nums[0][0], *nums[0].rbegin(), flag, nums, charMap, nums.size()-1);
if(ans==true){
cout<<"true"<<endl;
}else{
cout<<"false"<<endl;
}
return 0;
}problem3 最小平均响应时间安排
问题
0时刻,某人收到了N个工作,完成每个工作所需的时间为,工作的完成存在先后的依赖关系(即某些工作必须在其它工作之前完成)。一个人顺序完成N个工作,问如何安排完成工作的顺序,使得完成工作的平均响应时间最短,输出这样的顺序,在满足平均响应时间最短的情况下,要求字典序最小?(响应时间:从接收到工作到工作完成的时间)
分析
问题乍一看,拓扑排序,不过要求最短响应时间,当初以为是树形dp,直接放弃了,看了大家的分析,可后悔死人了,我想哭,可是我要假装坚强
说一下其他人的做法:拓扑排序+优先队列,对于当前可以处理的工作,优先选择完成时间最少的工作,如果存在多个完成时间最少的工作,选择编号最小点工作。
原因:可以先想想,如果没有依赖性的话,你会怎么做?肯定是希望等待时间最少,即所需时间少的工作优先完成(同时需要考虑字典序尽可能小)。现在是在它的基础上加了依赖性,每次能够只能当前没有前驱的工作集合中挑选用时最少的工作。也就是相比于无依赖性的时候,候选集合变小了,但是还是类似的思路,所以可以直接用优先队列挑选用时最少的工作
代码
测试样例忘了,只测了简单的样例
3 2
1 2 3
2 1
1 0
2,1,0,
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
struct Cmp{
bool operator()(const pair<int,int> &x, const pair<int,int> &y) const{
// 实现大于号, <first,second>分别表示cost, 编号
return x.second>y.second || (x.second==y.second && x.first>y.first);
}
};
int main(){
int N, M; cin>>N>>M;
vector<int> cost(N);
for(int i=0; i<N; i++) cin>>cost[i];
vector<int> indegree(N,0);
vector<vector<int>> edges(N);
for(int i=0; i<M; i++){
int prev, next; //假设输入依赖时工作编号从0开始
cin>>prev>>next;
indegree[next]++;
edges[prev].push_back(next);
}
priority_queue<pair<int,int>, vector<pair<int,int>>, Cmp> pque;
for(int i=0; i<N; i++){
if(indegree[i]==0){
pque.push(make_pair(cost[i], i));
}
}
vector<int> ans;
while(!pque.empty()){
auto node = pque.top(); pque.pop();
ans.push_back(node.second);
for(auto val : edges[node.second]){
indegree[val]--;
if(indegree[val]==0) pque.push(make_pair(cost[val], val));
}
}
// 输出安排结果
for(auto val : ans) cout<<val<<',';
cout<<endl;
return 0;
}problem4 最高金字塔
问题
给定N个积木,长宽均相等为,高度为1,重量为
,利用积木来搭金字塔,要求:每一层只有一块积木,上一层的积木的大小要严格小于当前层的积木的大小,每一层只能承受不大于自身重量的7倍的积木。问题金字塔最高能搭多少层?
分析
当高处的层确定后,高处层的具体配置我们并不关心,有无后效性,可以考虑动态规划
原问题N比较小,重量比较大,考虑用N相关的变量来描述状态
为了减少计算量,提前对积木按照由小到大的排序排序
状态: dp[i][j]表示第i个积木为底时,构造高度为j时所用的积木的最小重量
状态转移方差:dp[i][j] = min(dp[i][j], dp[k][j-1]+)(前提dp[k][j-1]状态合法,且第k个积木尺寸小于第i个积木
结果:代码只通过了95%,问题应该出在时间复杂度O(n^3)上
代码
#include<iostream>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
#include<map>
using namespace std;
int main(){
int N; cin>>N;
vector<pair<int,int>> nums(N);
for(int i=0; i<N; i++) cin>>nums[i].first;
for(int i=0; i<N; i++) cin>>nums[i].second;
nums.push_back(make_pair(0,0));
sort(nums.begin(), nums.end(), less<pair<int,int>>());
const int M = 0x7fffffff;
vector<vector<int>> dp(N+1, vector<int>(N+1,M));
dp[0][0] = 0;
// dp[i][j]表示第i个积木为底时,构造高度为j时所用的积木的最小重量
int ans = 0;
for(int i=1; i<=N; i++){
// 以第i块积木为低时
for(int k=0; k<i; k++){
if(nums[k].first<nums[i].first){ //长度满足条件
for(int j=0; j<=k; j++){
if(dp[k][j]!=M && dp[k][j]<=nums[i].second*7){
dp[i][j+1] = min(dp[i][j+1], dp[k][j]+nums[i].second);
ans = max(ans, j+1);
}
}
}
}
//for(int j=0; j<=i; j++) cout<<dp[i][j]<<' ';
//cout<<endl;
}
cout<<ans<<endl;
return 0;
}
京公网安备 11010502036488号