上海交通大学机试 需要二刷 *大数迪杰斯特拉/最小生成树+DFS/取模计算规律

基本思想:

首先的考虑是采用大数下的迪杰斯特拉来计算,比较繁琐,而且有多重边的情况;

其次可以采用稀疏图下的最小生成树算法来做;

原因:

1.给出的边集天然递增;

2.边满足后续边总大于之前边的和,所以天然可以保证贪心构造生成树,即为最短路径;

值得注意的是老生常谈的取模问题:

 方法一:

#include<iostream>
#include<vector>
#include<string>
using namespace std;

const int maxn = 110;
string SINF = "1";
int m, n;
string ma[maxn][maxn];
string dis[maxn];
bool vis[maxn];

void mutiple(string &s, int n) {
    int carry = 0;
    for (int i = s.size() - 1; i >= 0; i--) {
        int temp = (s[i] - '0')*n + carry;
        s[i] = temp % 10+'0';
        carry = temp / 10;
    }
    while (carry != 0) {
        s = char(carry % 10 + '0') + s;
        carry /= 10;
    }
}

bool cmp(string a, string b) {
    //如果a>b返回true;
    if (a.size() > b.size())
        return true;
    else if (a.size() == b.size())
        return a > b;
    else
        return false;
}

string cntmut(int k) {
    string s = "1";
    for (int i = 0; i < k; i++) {
        mutiple(s, 2);
    }
    return s;
}

string bigadd(string a, string b) {
    int len = a.size() - b.size();
    if (len > 0) {
        while (len != 0) {
            b = '0' + b;
            len--;
        }
    }
    else if(len<0){
        while (len != 0) {
            a = '0' + a;
            len++;
        }
    }
    int carry = 0;
    for (int i = a.size() - 1; i >= 0; i--) {
        int temp = carry + (a[i] - '0') + (b[i] - '0');
        a[i] = temp % 10+'0';
        carry = temp / 10;
    }
    if (carry != 0) {
        a = '1' + a;
    }
    while (a.size() > 1 && a[0] == '0')
        a.erase(0);
    return a;
}

void dij(int st) {
    dis[st] = "0";
    for (int u = 0; u < n; u++) {
        int index = -1;
        string Min = SINF;
        for (int i = 0; i < n; i++) {
            if (!vis[i] &&cmp(Min, dis[i])) {
                Min = dis[i];
                index = i;
            }
        }
        if (index == -1)
            return;
        vis[index] = true;
        for (int i = 0; i < n; i++) {
            string ss = bigadd(dis[index], ma[index][i]);
            if (!vis[i] && ma[index][i] != SINF && cmp(dis[i], ss))
                dis[i] = ss;
        }
        //cout << 1 << endl;
    }
}

void init() {
    fill(vis, vis + maxn, false);
    fill(ma[0], ma[0] + maxn * maxn, SINF);
    fill(dis, dis + maxn, SINF);
}

void output() {
    for (int i = 1; i < n; i++) {
        if (dis[i].size() > 5) {
            string s = dis[i].substr(dis[i].size() - 5, 5);
            while (s.size() > 1 && s[0] == '0')
                s.erase(0,1);
            cout << s <<endl;
        }
        else {
            cout << dis[i] << endl;
        }
    }
}

int main() {
    while (cin >> n >> m) {
        SINF = cntmut(m + 2);
        init();
        int a, b;
        for (int i = 0; i < m; i++) {
            cin >> a >> b;
            if(ma[a][b]==SINF)
                ma[a][b] = ma[b][a] = cntmut(i);
        }
        dij(0);
        output();
    }
}

方法二:

#include<iostream>
#include<vector>
#include<string>
#include<stdlib.h>
#include<queue>
using namespace std;

const int INF = 1000000;
const int maxn = 110;
int n, m;

int father[maxn];
int dist[maxn][maxn];
int dis[maxn];
bool vis[maxn];


int findfather(int n) {
    while (n != father[n])
        n = father[n];
    return n;
}

void Union(int x, int y) {
    int xx = findfather(x);
    int yy = findfather(y);
    father[xx] = yy;
}

void init() {
    for (int i = 0; i < n; i++) {
        father[i] = i;
    }
    fill(dist[0], dist[0] + maxn * maxn, INF);
    fill(dis, dis + maxn, INF);
    fill(vis, vis + maxn, false);
}

int cntmod(int k) {
    int num = 1;
    for (int i = 0; i < k; i++) {
        num = num % 100000;
        num *= 2;
        num = num % 100000;
    }
    return num;
}

void dfs(int st,int d) {
    dis[st] = d;
    vis[st] = true;
    for (int i = 0; i < n; i++) {
        if (dist[st][i] != INF&&!vis[i]) {
            int dd = d % 100000 + dist[st][i] % 100000;
            dfs(i, dd%100000);
        }
    }
    vis[st] = false;
}

int main() {
    while (cin >> n >> m) {
        int a, b;
        init();
        for (int i = 0; i < m; i++) {
            cin >> a >> b;
            int faa = findfather(a);
            int fab = findfather(b);
            if (faa != fab) {
                Union(a, b);
                dist[a][b] = dist[b][a] = cntmod(i);
            }
        }
        dfs(0, 0);
        for (int i = 1; i < n; i++) {
            cout << dis[i] << endl;
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/songlinxuan/p/12598945.html