Problem Description
Given a weighted graph
G
,a specific vertex
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;
}