坏键问题

坏键问题的本质就是图的单源最短路径问题
从坏键到其他所有键的路径中选择距离最短且连接点是好键的那条,这就是该坏键所需要的敲击次数
然后形成好键与坏键的敲击数组
遍历输入的字符串,进行累加敲击次数的动作

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;
    }
}``

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值