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 }

 

你可能感兴趣的:(code)