hihoCoder 1160 攻城略地

 

原图可能有多个连通分量,先DFS找出每个连通分量中最小节点,这些必然是要攻占的城市。

设 n 为节点数, m 为边数, cnt 为初始连通分量数,在剩下的边数不小于 m - (n - cnt) 的时候,图的连通性是不变的,也就是在这之前可以适当策略删边保持结果不变。

当边数小于等于 m - (n - cnt) 时,每删一条边,必然多一个连通分量,我们总可以做到让多出来这个连通分量的最小结点 是所有节点中除去已经选定的那些节点之外的最小节点,所以这时对节点以权值排序从小往大记到删够边数为止。

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 typedef long long LL;
 6 const int maxn = 1111111;
 7 const int maxm = 2111111;
 8 int n, m, k;
 9 int fst[maxn];
10 int wt[maxn];
11 int vis[maxn];
12 int nex[maxm], w[maxm], ntp;
13 void AddEdge(int a, int b)
14 {
15     nex[ntp] = fst[a];
16     w[ntp] = b;
17     fst[a] = ntp ++;
18 }
19 inline int min(int a, int b){return a < b ? a : b;}
20 void DFS(int nd, int &okcity)
21 {
22     if(vis[nd]) return;
23     vis[nd] = true;
24     if(okcity == -1 || wt[nd] < wt[okcity])
25         okcity = nd;
26     for(int i = fst[nd]; i != -1; i = nex[i])
27         DFS(w[i], okcity);
28 }
29 int main()
30 {
31     int t, ca;
32     for(scanf("%d", &t), ca = 1; ca <= t; ca ++)
33     {
34         int a, b;
35         scanf("%d%d%d", &n, &m, &k);
36         memset(fst, -1, sizeof(fst));
37         memset(vis, 0, sizeof(vis));
38         for(int i = 1; i <= n; i ++)
39             scanf("%d", &wt[i]);
40         ntp = 0;
41         for(int i = 0; i < m; i ++)
42         {
43             scanf("%d%d", &a, &b);
44             AddEdge(a, b);
45             AddEdge(b, a);
46         }
47         int cnt = 0;
48         LL ans = 0;
49         for(int i = 1; i <= n; i ++)
50         {
51             int okcity = -1;
52             DFS(i, okcity);
53             if(okcity != -1)
54                 cnt ++, ans += wt[okcity], vis[okcity] = 2;
55         }
56 
57         if((k -= m - (n - cnt)) > 0)
58         {
59             int i, j;
60             for(i = 1, j = 1; i <= n; i ++)
61                 if(vis[i] != 2) wt[j ++] = wt[i];
62             std::sort(wt + 1, wt + j);
63             for(int i = 1; k > 0 && i <= j; i ++)
64                 ans += wt[i], k --;
65         }
66         printf("Case #%d: %lld\n", ca, ans);
67     }
68     return 0;
69 }

 

posted @ 2015-04-27 11:30  CSGrandeur  阅读(424)  评论(0编辑  收藏  举报