POJ 1679 次小生成树 Kruskal +DFS优化

来源:互联网 发布:数据化决策 编辑:程序博客网 时间:2024/06/16 08:32

http://poj.org/problem?id=1679
看了网上大部分都是直接多次跑 kruskal的,数据大了会耗时间。先深搜一次跑出最小生成树各点路径的最大边权,存在MAXCST[I][J]表示i——》J的路径最大的边的边权
然后逐一减去这个边加上不是最小生成树的边再取最小值便是次小生成树了

#include<iostream>#include<vector>#include<algorithm>using namespace std;int father[105];//父亲节点数组bool used[10005];//标记边是否处于最小生成树内int cost[105][105];//记录最小生成树2点的花费int maxcost[105][105];//存最小生成树任意2点的最大路径bool mark[105];//最小生成树标记vector<int> vis;//记录哪些点在最小生成树内int ans;//最小生成树的权值之和int n, m;bool hash1[105];struct node{    int from, to, w;};bool cmp(node &a,node &b){    if (a.w<b.w)        return true;    return false;}node edug[10005];vector<int> shu[105];void init(){    memset(mark, false, sizeof(mark));    memset(used, false, sizeof(used));    memset(maxcost, -1, sizeof(maxcost));    memset(cost, -1, sizeof(cost));    for (int i = 0; i <= n; i++)    {        father[i] = i;    }    ans = 0;    vis.clear();}int find(int x){    if (father[x] == x)        return x;    return father[x] = find(father[x]);}bool combine(int x,int y,int w,int i){                            int fx = find(x);    int fy = find(y);    if (fx != fy)    {        used[i] = true;        father[fy] = fx;        shu[x].push_back(y);//建立最小生成树的领接表,这里是无向变        shu[y].push_back(x);        ans+=cost[x][y] = cost[y][x] = w;//统计和记录最小生成树2点花费        if (!mark[x])//记录哪些点在最小生成树内        {            mark[x] = true;            vis.push_back(x);        }        if (!mark[y])        {            mark[y] = true;            vis.push_back(y);        }        return true;    }    return false;}void dfs(int f, int t, int w, int root)//深搜处理最小树的任意2点的最大路径{    if (hash1[f])//找过了        return;    hash1[f] = true;    for (int i = 0; i < shu[f].size(); i++)    {        if (shu[f][i] == t)            continue;        maxcost[root][shu[f][i]] = maxcost[shu[f][i]][root] = max(w, cost[f][shu[f][i]]);//以前走过的路径和当前路径的权取最大值        dfs(shu[f][i], f, max(w, cost[f][shu[f][i]]), root);    }}int krusal(){    int num = 0;    sort(edug,edug + m,cmp);    for (int i = 0; i < m; i++)    {        if (combine(edug[i].from, edug[i].to, edug[i].w, i))            num++;        if (num == n - 1)            break;    }    for (int i = 0; i < vis.size(); i++)    {        memset(hash1, false, sizeof(hash1));        dfs(vis[i], -1, 0, vis[i]);    }    int sum = 0x3f3f3f3f;    for (int i = 0; i < m; i++)    {        if (used[i])            continue;        int u = edug[i].from;        int v = edug[i].to;        int w = edug[i].w;        sum = min(ans + w - maxcost[u][v],sum);//逐一减去这个边加上不是最小生成树的边再取最小值便是次小生成树了    }    if (sum == ans)        cout << "Not Unique!" << endl;    else        cout << ans << endl;    return 0;}int main(){    int t;    cin >> t;    while (t--)    {        cin >> n >> m;        init();        for (int i = 0; i < m; i++)        {            cin >> edug[i].from >> edug[i].to >> edug[i].w;        }        krusal();    }}
0 0
原创粉丝点击