URAL 1806 Mobile Telegraphs

URAL_1806

    这个题目思路比较明显,将边的关系找出来之后做最短路即可,但是由于N巨大,直接判断两个字符串能否转化是划不来的。

    于是不妨将所有字符串放到哈希表中,然后对于当前字符串,枚举这个字符串改变一位、交换两位的情况,然后看能否在哈希表中找到变化之后的字符串,这样对于每个字符串至多枚举200种情况,复杂度还是可以接受的。

#include<stdio.h>
#include<string.h>
#define MAXD 50010
#define HASH 1000003
#define INF 0x3f3f3f3f
int N, D, cost[15], head[HASH], next[MAXD];
char b[MAXD][15], code[15];
int dis[MAXD], pre[MAXD], tree[4 * MAXD];
int hash(char *str)
{
    int i, h = 0, seed = 131;
    while(*str)
        h = h * seed + *(str ++);
    return (h & 0x7fffffff) % HASH;    
}
void Insert(int s)
{
    int h = hash(b[s]);
    next[s] = head[h];
    head[h] = s;    
}
int search(char *str)
{
    int i, h = hash(str);
    for(i = head[h]; i != -1; i = next[i])
        if(strcmp(b[i], str) == 0)
            break;
    return i;
}
void init()
{
    int i;
    for(i = 0; i < 10; i ++)
        scanf("%d", &cost[i]);
    memset(head, -1, sizeof(head));
    for(i = 1; i <= N; i ++)
    {
        scanf("%s", b[i]);
        Insert(i);    
    }
}
void update(int i)
{
    for(; i ^ 1; i >>= 1)
        tree[i >> 1] = dis[tree[i]] < dis[tree[i ^ 1]] ? tree[i] : tree[i ^ 1];
}
void Swap(char &x, char &y)
{
    char t;
    t = x, x = y, y = t;    
}
void dfs(int cur, int n)
{
    if(cur == 1)
    {
        printf("%d\n%d", n, cur);
        return ;
    }
    dfs(pre[cur], n + 1);
    printf(" %d", cur);
}
void solve()
{
    int i, j, x, y;
    for(D = 1; D < N + 2; D <<= 1);
    memset(tree, 0, sizeof(tree));
    memset(dis, 0x3f, sizeof(dis));
    dis[1] = 0, pre[1] = 0, tree[D + 1] = 1, update(D + 1);
    while(x = tree[1])
    {
        strcpy(code, b[x]);
        tree[D + x] = 0, update(D + x);
        for(i = 0; i < 10; i ++)
            for(j = '0'; j <= '9'; j ++)
                if(j != code[i])
                {
                    code[i] = j;
                    y = search(code);
                    if(y != -1 && dis[x] + cost[i] < dis[y])
                        dis[y] = dis[x] + cost[i], pre[y] = x, tree[D + y] = y, update(D + y);
                    code[i] = b[x][i];
                }
        for(i = 0; i < 10; i ++)
            for(j = i + 1; j < 10; j ++)
                if(code[i] != code[j])
                {
                    Swap(code[i], code[j]);
                        y = search(code);
                    if(y != -1 && dis[x] + cost[i] < dis[y])
                        dis[y] = dis[x] + cost[i], pre[y] = x, tree[D + y] = y, update(D + y);
                    Swap(code[i], code[j]);    
                }
    }
    if(dis[N] == INF)
        printf("-1\n");    
    else
    {
        printf("%d\n", dis[N]);
        dfs(N, 1);
        printf("\n");
    }
}
int main()
{
    while(scanf("%d", &N) == 1)
    {
        init();
        solve();    
    }
    return 0;    
}
原文地址:https://www.cnblogs.com/staginner/p/2586569.html