Gym - 101502I- Move Between Numbers (最短路) (Dijkstra)

You are given n magical numbers a 1, a 2, ..., a n, such that the length of each of these numbers is 20 digits.

You can move from the i th number to the j th number, if the number of common digits between a i and a j is exactly 17 digits.

The number of common digits between two numbers x and y is computed is follow:

.

Where countX i is the frequency of the i th digit in the number x, and countY i is the frequency of the i th digit in the number y.

You are given two integers s and e, your task is to find the minimum numbers of moves you need to do, in order to finish at number a e starting from number a s.

Input

The first line contains an integer T (1 ≤ T ≤ 250), where T is the number of test cases.

The first line of each test case contains three integers ns, and e (1 ≤ n ≤ 250) (1 ≤ s, e ≤ n), where n is the number of magical numbers, s is the index of the number to start from it, and e is the index of the number to finish at it.

Then n lines follow, giving the magical numbers. All numbers consisting of digits, and with length of 20 digits. Leading zeros are allowed.

Output

For each test case, print a single line containing the minimum numbers of moves you need to do, in order to finish at number a e starting from number a s. If there is no answer, print -1.

Example

Input
1
5 1 5
11111191111191111911
11181111111111818111
11811171817171181111
11111116161111611181
11751717818314111118
Output
3

Note

In the first test case, you can move from a 1 to a 2, from a 2 to a 3, and from a 3 to a 5. So, the minimum number of moves is 3 moves.

题意:给你n个长度为20的串(字符串只会出现0-9的数字),你以第 s 的字符串为起点到达终点为 e 的字符串最短路径
   两串字符中有17个数相同就说明两串字符间有一条边联系。即 ans += min(第一个数0-9出现的次数,第二个数0-9出现的次数) = 17的时候,两边建立联系

思路:建图,然后最短路跑一遍,Dijkstra 复杂度 O(n*n)

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%d",&a)
#define pr(a) printf("%d\n",a);
#define SC(n,m) scanf("%d%d",&n,&m)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9 + 7;
const int Maxn = 1010;
const int M = Maxn * 20;
const double pi = acos(-1.0);
const double eps = 1e-8;
/*
* 单源最短路径,Dijkstra算法,邻接矩阵形式,复杂度为O(n^2)
* 可更改路径权类型,但是权值必须为非负
* Dijkstra算法寻找的是下一个离给定顶点(单源)最近的顶点。
*/
int vis[Maxn];//用来标记0和1  表示这个点是否被选择过
int G[Maxn][Maxn];//邻接矩阵用来存储图的信息
int dis[Maxn];//记录任意一点到这个点的最近距离
char str[Maxn][Maxn];
int a[Maxn][Maxn];
int n, s, e, minl, minid, sum;
void Dijkstra()
{
    mem(vis, 0);
    sum = 0;
    for (int i = 1; i <= n; i++) {
        dis[i] = G[s][i]; //s是起点
    }
    dis[s] = 0;//起点到起点距离为0
    vis[s] = 1;//选择起点
    /*查找到原集合的最短的边,循环n-1次*/
    for (int i = 1; i <= n-1; i++)
    {
        minl = INF;
        minid = 0;
        for (int j = 1; j <= n; j++)
        {
            if (vis[j] == 0 && dis[j] < minl)//循环找出dis的最小边的节点
            {
                minl = dis[j];
                minid = j;
            }
        }
        vis[minid] = 1; //每并入一个点都要对原来的边进行修正,保证任意时刻源点到目标点的距离都是最短的。
        for (int j = 1; j <= n; j++)//添入新点后更新最小距离
        {
            if (!vis[j] && dis[j] > dis[minid] + G[minid][j])
                dis[j] = dis[minid] + G[minid][j];
        }
    }
}
int main(){
    int t;
    sc(t);
    while (t--) {
        mem(dis, INF);
        mem(G, INF);
        mem(a, 0);
        scanf("%d%d%d", &n, &s, &e);
        FOR(i, 1, n) {
            scanf("%s", str[i]);
            for (int j = 0; j < 20; j++) {
                a[i][str[i][j] - '0']++;
            }
        }
        FOR(i, 1, n) {
            FOR(j, i + 1, n) {
                int ans = 0;
                for (int k = 0; k < 10; k++) {
                    ans += min(a[i][k], a[j][k]);
                }
                if (ans == 17) {
                    G[i][j] = G[j][i] = 1;
                }
            }
        }
        Dijkstra();
        if (dis[e] == INF)
            printf("-1\n");
        else 
            pr(dis[e]);
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/AlexLINS/p/12726585.html