坏键问题的本质就是图的单源最短路径问题
从坏键到其他所有键的路径中选择距离最短且连接点是好键的那条,这就是该坏键所需要的敲击次数
然后形成好键与坏键的敲击数组
遍历输入的字符串,进行累加敲击次数的动作
constexpr int INF = 1000;
int G[26][26];
bool visited[26];
int dist[26];
bool dijstra(int s){
memset(visited,0,26);
fill(dist,dist + 26,INF);
dist[s] = 1;
for(int i = 0 ; i < 26 ; ++i){
int u = -1;
int min = INF;
for(int j = 0 ; j < 26 ; ++j){
if(visited[j] == false && dist[j] < min){
u = j;
min = dist[j];
}
}
if( u == -1)
return false;
visited[u] = true;
for(int v = 0 ; v < 26 ; ++v)
if(visited[v] == false && G[u][v] != INF && dist[u]+G[u][v] < dist[v])
dist[v] = dist[u] + G[u][v];
}
return true;
}
set<int> goodKeys;
int findShortest(int s){
dijstra(s);
int min = INF;
for(int i = 0 ; i < 26 ; ++i){
if(dist[i] != INF && dist[i] != 1 && (dist[i] < min) && (goodKeys.find(i) != goodKeys.end()))
min = dist[i];
}
if(min == INF)
return -1;
return min;
}
int tapCount[26];
int main(int argc, const char * argv[]) {
int t;
cin >> t;
for(int i = 0 ; i < t ; ++i){
//图、容器初始化
fill(G[0],G[0] + 26 * 26 , INF);
goodKeys.clear();
for(int j = 0 ; j < 26 ;++j)
goodKeys.insert(j);
//输入规则构建图
int n;
cin >> n;
char end,begin;
for(int j = 0 ; j < n ; ++j){
cin >> end;
cin >> begin;
G[begin -'a'][end - 'a'] = 1;
}
//输入坏键
int badNumber;
cin >> badNumber;
char badKey;
for(int j = 0 ; j < badNumber ; ++j){
cin >> badKey;
goodKeys.erase(badKey - 'a');
}
//构建每个键的敲击次数数组
fill(tapCount,tapCount + 26 , -1);
for(int j = 0 ; j < 26 ; ++j){
if(goodKeys.find(j) != goodKeys.end())
tapCount[j] = 1;
else{
tapCount[j] = findShortest(j) ;
}
}
//统计敲击次数
char input[200];
scanf("%s",input);
size_t length = strlen(input);
int totalTapCount = 0;
bool hasResult = true;
for(int j = 0 ; j < length ; ++j){
if(tapCount[input[j]-'a'] != -1){
totalTapCount += tapCount[input[j]-'a'];
}
else{
cout << -1 << endl;
hasResult = false;
break;
}
}
if(hasResult)
cout << totalTapCount << endl;
}
}``