【題意】:給出n個點,m條邊,邊分為兩種,一種是A公司的,一種是B公司的。邊上有權值,問用n-1條邊把n個點連起來的最小費用是多少,其中A公司的邊剛好有k條。題目保證有解。

【題解】:很明顯看到是求一顆最小生成樹,不過有一個限制就是剛剛好有k條邊是A公司的。想了很久不會做,看別人代碼的。二分出一個最大值delta使得A公司的邊加上這個值后再求MST時A公司的邊有大于等于k條,然后答案就是cost of MST - k * delta。思想其實是加上一個delta值去逼近答案,最后可以求出這樣的MST,如果最后求出的MST的A公司的邊多于k條,一定存在與A公司等效且等價的B公司邊,替換過來即可。

【代碼】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 #include "string"
 9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 #include "set"
13 #include "utility"
14 using namespace std;
15 typedef pair<intint> pii;
16 #define pb push_back
17 #define mp make_pair
18 #define fi first
19 #define se second
20 #define sof(x) sizeof(x)
21 #define lc(x) (x << 1)
22 #define rc(x) (x << 1 | 1)
23 #define lowbit(x) (x & (-x))
24 #define ll long long
25 struct Edge {
26     int u, v, w, id;
27     Edge(){}
28     Edge(int _u, int _v, int _w, int _id) {
29         u = _u, v = _v, w = _w, id = _id;
30     }
31     bool operator<(const Edge &x) const {
32         if(w != x.w) return w < x.w;
33         else return id < x.id;
34     }
35 }et[2][100050], e;
36 int tot, tot1;
37 int n, m, k, cost;
38 int fa[50050];
39 
40 int find(int x) {
41     return (x == fa[x]) ? x : fa[x] = find(fa[x]);
42 }
43 
44 bool merge(int u, int v) {
45     u = find(fa[u]), v = find(fa[v]);
46     if(u != v) {
47         fa[u] = v;
48         return true;
49     } else return false;
50 }
51 
52 bool check(int w) {
53     cost = 0;
54     int cnt = 0;
55     for(int i = 0; i < n; i++) fa[i] = i;
56     int i = 0, j = 0;
57     while(i < tot || j < tot1) {
58         if(et[0][i].w + w <= et[1][j].w) {
59             e = et[0][i++];
60             e.w += w;
61         } else e = et[1][j++];
62         if(merge(e.u, e.v)) {
63             if(!e.id) cnt++;
64             cost += e.w;
65         }
66     }
67     return cnt >= k;
68 }
69 
70 int main() {
71     int Case = 1;
72     while(~scanf("%d%d%d", &n, &m, &k)) {
73         tot = tot1 = 0;
74         for(int i = 0; i < m; i++) {
75             int u, v, w, id;
76             scanf("%d%d%d%d", &u, &v, &w, &id);
77             if(id) et[1][tot1++] = Edge(u, v, w, id);
78             else et[0][tot++] = Edge(u, v, w, id);
79         }
80         sort(et[0], et[0] + tot);
81         sort(et[1], et[1] + tot1);
82         et[0][tot].w = et[1][tot1].w = 1 << 30;
83         int l = -100, r = 100;
84         int w;
85         while(l <= r) {
86             int mid = (l + r) / 2;
87             if(check(mid)) w = mid, l = mid + 1;
88             else r = mid - 1;
89         }
90         check(w);
91         printf("Case %d: %d\n", Case++, cost - w * k); 
92     }
93     return 0;
94 }
95