单点度限制最小生成树存代码

Problem Description

Given a weighted graph G ,a specific vertex v0 and an integer K , find a spanning tree T with restriction deg( v0 )= K (we don’t care about other vertices’ degrees) and minimize the weight sum of edges of T.

Algorithm

Refer to 《最小生成树问题的拓展》汪汀. Thanks to Prof. Carvalho, Lemma 1 can be proved through modeled by matchings.

Code

example:http://codeforces.com/contest/125/problem/E

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <utility>
#include <cstring>
#include <map>
#include <climits>
#include <queue>
#include <cmath>
#include <set>
#include <stack>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned UI;
typedef pair<int, int> PAIR;

const int MAXN(5010);
const int MAXE(200010);
const int MAXK(100010);
const int MAXL(10);
const int MAXC(2);
const int INF((INT_MAX - 1) / 2);
const int F(0);

template<typename T>
inline bool checkmax(T &a, const T &b) {
    return b > a ? ((a = b), true) : false;
}

template<typename T>
inline bool checkmin(T &a, const T &b) {
    return b < a ? ((a = b), true) : false;
}

template<typename T>
inline T ABS(T a) {
    return a < 0 ? -a : a;
}

double dis(double x1, double y1, double x2, double y2) {
    return sqrt((y2 - y1)*(y2 - y1) + (x2 - x1)*(x2 - x1));
}

double dis2(double x1, double y1, double x2, double y2) {
    return (y2 - y1)*(y2 - y1) + (x2 - x1)*(x2 - x1);
}

struct FS {
    int fa[MAXN];
    void init(int n) {
        for (int i = 0; i < n; ++i) fa[i] = i;
    }
    int find(int u) {
        if (fa[u] != u)
            fa[u] = find(fa[u]);
        return fa[u];
    }
} fs;

struct E {
    int u, v, ti;
    E *next;
    E(int u_, int v_, int w_, E *n_) :u(u_), v(v_), next(n_) {}
    E(){}
};

int aA[MAXE / 2], bA[MAXE / 2], cA[MAXE / 2];
int order[MAXE / 2];
int adj[MAXN], best[MAXN], cand[MAXN];
bool choose[MAXE / 2];

struct G {
    E *first[MAXN];
    E edge[MAXE], *rear;
    void init(int n) {
        memset(first, 0, sizeof(first[0])*n);
        rear = edge;
    }
    void addEdge(int u, int v, int ti) {
        rear->ti = ti;      //ti存储边的索引
        rear->u = u;
        rear->v = v;
        rear->next = first[u];
        first[u] = rear++;
    }
    void dfs(int u, int f) {
        for (E *i = first[u]; i; i = i->next) {
            int ti = i->ti;
            int v = i->v;
            if (!choose[ti] || v == f) continue;
            if (u != 0) {
                best[v] = cA[ti];
                cand[v] = ti;
                if (checkmax(best[v], best[u]))
                    cand[v] = cand[u];
            }
            else {
                best[v] = -INF;
                cand[v] = -1;
            }
            dfs(v, u);
        }
    }
} g;

bool cmp(int a, int b) {
    return cA[a] < cA[b];
}

vector<int> restMST(int n, int K, vector<pair<PAIR, int> > link) { //deg(v_0)=K条件下的MST, n为点数,link为无向非环边集
    int m = (int)link.size();
    for (int i = 0; i < m; ++i) {
        pair<PAIR, int> t = link[i];
        aA[i] = t.first.first;
        bA[i] = t.first.second;
        cA[i] = t.second;
        order[i] = i;
        if (aA[i] > bA[i]) swap(aA[i], bA[i]);
    }
    sort(order, order + m, cmp);
    fs.init(n);
    for (int i = 0; i < m; ++i) {
        int ti = order[i];
        choose[ti] = false;
        if (aA[ti] == 0) continue;
        int r1 = fs.find(aA[ti]), r2 = fs.find(bA[ti]);
        if (r1 == r2) continue;
        fs.fa[r2] = r1;
        choose[ti] = true;
    }
    int components = 0; //G-v_0形成的连通分量数
    for (int i = 1; i < n; ++i){
        adj[i] = -1;
        cand[i] = -1;
        if (fs.fa[i] == i)
            ++components;
    }
    if (components > K) return vector<int>(1, -1);
    int cnt = 0;
    for (int i = 0; i < m; ++i) {
        int ti = order[i];
        if (aA[ti] != 0) continue;
        adj[bA[ti]] = ti;
        int r = fs.find(bA[ti]);
        if (cand[r] == -1) {
            cand[r] = 1;     //这里是临时借用cand表示某个连通分量是否已经和v_0相连
            choose[ti] = true;
            ++cnt;
        }
    }
    if (cnt != components) return vector<int>(1, -1);
    g.init(n);
    for (int i = 0; i < m; ++i) {
        if (!choose[i]) continue;
        g.addEdge(aA[i], bA[i], i);
        g.addEdge(bA[i], aA[i], i);
    }
    while (components < K) {
        g.dfs(0, -1);
        int tBest = INF, tCand;
        for (int i = 1; i < n; ++i) {
            int ti = adj[i];
            if (ti == -1 || choose[ti]) continue;
            if (checkmin(tBest, cA[ti] - best[i]))
                tCand = i;
        }
        if (tBest == INF) return vector<int>(1, -1);
        int ti = adj[tCand];
        g.addEdge(aA[ti], bA[ti], ti);
        g.addEdge(bA[ti], aA[ti], ti);
        choose[ti] = true;
        ti = cand[tCand];
        choose[ti] = false;
        ++components;
    }
    vector<int> ret;
    for (int i = 0; i < m; ++i)
        if (choose[i])
            ret.push_back(i);
    return ret;
}

int main() {
    int n, m, K;
    scanf("%d%d%d", &n, &m, &K);
    vector<pair<PAIR, int> > link;
    int u, v, w;
    for (int i = 0; i < m; ++i) {
        scanf("%d%d%d", &u, &v, &w);
        --u;
        --v;
        if (u == v) continue;
        link.push_back(make_pair(PAIR(u, v), w));
    }
    vector<int> ans = restMST(n, K, link);

    if (ans.size() == 1 && ans[0] == -1)
        printf("-1\n");
    else {
        printf("%d\n", ans.size());
        bool pr(false);
        for (int i = 0; i < ans.size(); ++i) {
            if (pr) printf(" ");
            pr = true;
            printf("%d", ans[i]+1);
        }
        if(pr) printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值