相当有难度的一道题。可以用分阶段的贪心算法做,但需要大致证明局部最优解可以收敛到全局最优。
假设有服务器ABCD,访问序列去除掉无关项、只剩下CBDA...CD
假设A是一步之内可以到达的最远点。由于要从A换成别的服务器,第二步可以到达除A外单步之内最远的字母。
又由于A是从起点出发、第一步可到达的最远点,则其它字母必然在A之前出现至少一次(否则假设不成立)。
假设第一步取的不是A而是其他字母,则必然有:第二步到达的位置<=第一步取A在第二步可到达的位置。
【详细论证】任取非A字母B,也可以换成CD
第一步从起点到B,则第二步从B到最远的非B字母,也就是字母A、或者非A非B的字母X
//注意,我们假设了A是第一步可到达的最远位置,故第一个B在第一个A之前
如果第二步选A,显然刚到达第一个A,肯定要比第一步就选A要近
如果这个字母在第一个B和第一个A之间出现,那么甚至都摸不到第一个A
如果这个字母在第一个B和第一个A之间不出现,那么第二步到达的距离一样远
因此,在本题中使用贪心算法可以从局部最优收敛到全局最优。相当于只是剪了个枝。
【分阶段贪心】自己随便起了个名字,就是每步都选能走最远距离的字母(代理服务器),直到抵达目标
【需要注意的坑】vector的pop_back是删除最后一个,不是第一个,删第一个要用erase
#include<iostream>
#include<vector>
#include<map>
#include<string>
#include<algorithm>
using namespace std;
void Question7_1(){//习题7.1 清华大学 代理服务器
int n,m;
while(cin>>n){
string ip;
//初始化代理服务器
map<string,vector<int>> agent;
vector<int> empty;
empty.push_back(5000);//5000表示在访问序列中未出现、可以直接干到底
for(int i=0;i<n;i++){
cin>>ip;
agent[ip] = empty;
}
cin>>m;
//初始化访问列表
vector<string> visit;
for(int j=0;j<m;j++){
cin>>ip;
visit.push_back(ip);
//要访问的ip不是代理服务器,可以不用管
map<string,vector<int>>::iterator finder = agent.find(ip);
if(finder==agent.end()) continue;
//访问的ip是代理服务器时,记录在访问列表中出现的位置
//也就相当于这个代理服务器每次可到达的最远距离
//注意补正,如果不能直接干到底就把那个5000给去掉
if(finder->second[0]==5000) finder->second.pop_back();
finder->second.push_back(j);
}
//分阶段贪心策略
int step = 0;
string ban;
int maxPos = 0;
string maxKey;
//只有一台服务器且不能直通末尾,无法完成目标
if(n==1&&agent.begin()->second[0]<m){
step = -1;
}
while(step!=-1 && maxPos<m){
//搜寻本轮能到达的最远距离
map<string,vector<int>>::iterator it = agent.begin();
while(it!=agent.end()){
//上一轮要换代理服务器,因此本轮ban掉这个
if(it->first!=ban && it->second[0]>maxPos){//寻找最远
maxKey = it->first;
maxPos = it->second[0];
}
it++;
}
ban = maxKey;
//到达末尾,跳出
if(maxPos>=m) break;
//否则,清除掉已经经过的位置
it = agent.begin();
while(it!=agent.end()){
while(it->second[0]<=maxPos){
it->second.erase(it->second.begin());//pop_back是删除最后一个,第一个要用erase
if(it->second.size()==0){
//不应该erase掉,应该当作可以直达末尾、填充一个5000
it->second.push_back(5000);
break;
}
}
it++;
}
//所经过的步数+1
step++;
}
//最终输出
cout<<step<<endl;
}
}
int main(){
Question7_1();
return 0;
}

京公网安备 11010502036488号