经典贪心问题,刚开始怎么也看不懂题,寻思着要想切换次数尽可能少,直接找个和所有服务器都不相同的代理服务器或者找个最迟出现的和代理服务器相同的服务器不就好了。。想了很久才意识到这个最迟出现的代理服务器相同的服务器可以多次出现,这样在切换这个最迟服务器之前(要想抵达这里代理服务器ip必须和这个服务器相同)前面由于也是同名代理服务器所以必定会卡死,所以要考虑到要访问服务器出现多次的情况。
既然如此,问题就转化为每次都选取一个代理服务器,使他代理的服务器尽可能多。由于服务器访问是顺序访问,所以可以用步数代替,故转化为每次选取一个代理使他走的步数尽可能多。由于无后效性(当前一步和前一步无关),贪心策略达成。
这题还是卡了我很久,原因在于step数组初始化位置错误,然后答案还显示不出错,很隐蔽,用排除法才找到错。。。还有,本题需要考虑特殊情况,出现无法抵达的情况只可能是代理只有一个的时候,因为一旦一个以上,都可以通过切换改变当前代理后通过。综上,好题。
说起贪心,贪心思想就是只要找出当前最优解即可,说起来简单,可是题目好多时候灵活性过于强,和DP有类似之处,感觉有思路就是在有限时间内写不出来。对于这种情况,我认为如果不是参加比赛的话可以适当放弃,毕竟任何人智商还是有差距的,拿自己的短板刚对手的长项,并不合理。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <stack>
#include <cctype>
#include <cmath>
#include <climits>
using namespace std;
const int MAXN = 100005;
const int INF = INT_MAX;
int main(){
// freopen("in.txt", "r", stdin);
int n, m;
int step[1005];
while(~scanf("%d", &n)){
//输入
string server[5005];
string agent[1005];
for(int i = 0; i < n; i++){
cin >> agent[i];
}
scanf("%d", &m);
for(int i = 0; i < m; i++){
cin >> server[i];
}
if(n == 1){
bool tag = false;
for(int i = 0; i < m; i++){
if(server[i] == agent[0]) tag = true;
}
if(tag) printf("-1\n");
else printf("0\n");
continue;
}
//贪心策略:每一步走远一点,即每一次使用的代理服务器都要尽可能多代理计算机
int start = 0, end = m-1;
int ans = 0;
bool flag = false;
while(start != end){
memset(step, 0, sizeof(step));//每一次起步时步数都要清零!!!
int maxstep = 0;
for(int i = 0; i < n; i++){
int j = start;//继承步数
while(agent[i] != server[j]){
if(j >= end){
flag = true;
break;
}
j++;
step[i]++;
}
maxstep = max(maxstep, step[i]);//找出最大值
if(flag) break;
}
if(flag){
start = end;
continue;
}
// printf("%d\n", maxstep);
start += maxstep;
ans ++;
}
printf("%d\n", ans);
}
return 0;
}