Kingdoms 枚举+最小生成树

来源:互联网 发布:宿迁网络电视台 编辑:程序博客网 时间:2024/06/15 16:02

A kingdom has n cities numbered 1 to n, and some bidirectional roads connecting cities. The capital is always city 1.
After a war, all the roads of the kingdom are destroyed. The king wants to rebuild some of the roads to connect the cities, but unfortunately, the kingdom is running out of money. The total cost of rebuilding roads should not exceed K.
Given the list of m roads that can be rebuilt (other roads are severely damaged and cannot be rebuilt), the king decided to maximize the total population in the capital and all other cities that are connected (directly or indirectly) with the capital (we call it “accessible population”), can you help him?
Input
The first line of input contains a single integer T (T<=20), the number of test cases.
Each test case begins with three integers n(4<=n<=16), m(1<=m<=100) and K(1<=K<=100,000).
The second line contains n positive integers pi (1<=pi<=10,000), the population of each city.
Each of the following m lines contains three positive integers u, v, c (1<=u,v<=n, 1<=c<=1000), representing a destroyed road connecting city u and v, whose rebuilding cost is c.
Note that two cities can be directly connected by more than one road, but a road cannot directly connect a city and itself.
Output
For each test case, print the maximal accessible population.

Sample Input
2
4 6 6
500 400 300 200
1 2 4
1 3 3
1 4 2
4 3 5
2 4 6
3 2 7
4 6 5
500 400 300 200
1 2 4
1 3 3
1 4 2
4 3 5
2 4 6
3 2 7
Sample Output
1100
1000
题意:有n个城市和m条路,k块钱,每个城市有一个权值。国王居住在1号城市,现在问你如何选出一些边总费用不超过k,使得跟1号城市连接的所有城市权值最大
思路:数据量比较小,城市只有16个,所有我们可以用状态保存下16个城市所有的状态,1表示已经选入,0表示未选入。
这样状态总数也只有1<<16=65536 所以我们可以枚举所有的状态,然后用最小生成树求出连通这些为1的结点所需要的最小费用是否大于k,枚举完后在费用<=k的状态里面取权值最大的即可。 注意1号城市一定会选入,这样状态可以少一维。
(转自http://blog.csdn.net/acm_cxq/article/details/52192026)

/*  prim算法    AC:112ms*/#include <iostream>#include <string>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>#include <algorithm>#include <queue>#include <map>#include <vector>#define MM(s,q) memset(s,q,sizeof(s))#define INF 0x3f3f3f3f#define MAXN 1005#define Lchild id<<1#define Rchild (id<<1)+1#define FILE  freopen("data.in","r",stdin)using namespace std;int popu[MAXN], mp[50][50],  ans, vis[50], vis1[50];void prime(int status, int n, int KK) {    int exist[20], cnt = 0, sum = 0;    for (int i = 1; i <= n; i++) {        if (status & (1 << (i - 1)))            exist[cnt++] = i,sum+=popu[i];    }    int dist[20];    MM(dist, INF);    MM(vis,0);    dist[1] = 0;    int cost = 0;    for (int i = 1; i <= cnt; i++) {        int k = INF, pos;        for (int j = 0; j < cnt; j++) {            int a = exist[j];            if (!vis[a] && dist[a] < k)                k = dist[a], pos = a;        }        vis[pos] = 1;        cost += k;        if (cost > KK) return;        for (int j = 0; j < cnt; j++) {            int a = exist[j];            if (!vis[a] && dist[a] > mp[pos][a])                dist[a] = mp[pos][a];        }    }    if (cost <= KK && sum > ans)        ans = sum;}int main() {    int T, n, m, k, u, v, w;    cin >> T;    while (T--) {        MM(mp, INF);        cin >> n >> m >> k;        for (int i = 1; i <= n; i++) cin >> popu[i];        for (int i = 1; i <= m; i++) {            scanf("%d%d%d", &u, &v, &w);            mp[u][v] = mp[v][u] = min(w, mp[u][v]);        }        ans = 0;        int status = 1 << n;        for (int i = status - 1; i >= 1; i--) {            if (!(i & 1)) continue;            prime(i, n, k);        }        cout << ans << endl;    }}
/*    Kruskal 算法    AC:580ms */#include <iostream>#include <string>#include <cstring>#include <cstdio>#include <cmath>#include <cstdlib>#include <algorithm>#include <queue>#include <map>#include <vector>#define MM(s,q) memset(s,q,sizeof(s))#define INF 0x3f3f3f3f#define MAXN 1005#define Lchild id<<1#define Rchild (id<<1)+1#define FILE  freopen("data.in","r",stdin)using namespace std;struct Edge {    int u, v, w;    Edge() {}    Edge(int a, int b, int c) {        u = a, v = b, w = c;    }    bool operator < (const Edge a)const {        return w > a.w;    }} tmp;int popu[MAXN], mp[50][50], F[MAXN], ans, vis[50][50], vis1[50];int Find(int x) {    return F[x] == x ? x : (F[x] = Find(F[x]));}void  Kruskal(int status, int n, int KK) {    int k = 1, exist[20], cnt = 0, sum = 0;    priority_queue<Edge> Q ;    for (int i = 1; i <= n; i++) {        if (status & (1 << (i - 1)))            exist[cnt++] = i, sum += popu[i];    }    for (int i = 0; i < cnt; i++)        for (int j = 0; j < cnt; j++) {            int a = exist[i], b = exist[j];            Q.push(Edge(a, b, mp[a][b]));        }    for (int i = 1; i <= n; i++)F[i] = i;    int cost = 0;    while (!Q.empty()) {        tmp = Q.top();        Q.pop();        int u = tmp.u, v = tmp.v, w = tmp.w;        int fa = Find(u), fb = Find(v);        if (fa == fb) continue;        F[fb] = fa;        cost += w;        if (cost > KK) return;    }    if (cost <= KK && sum > ans)        ans = sum;}int main() {    int T, n, m, k, u, v, w;    cin >> T;    while (T--) {        MM(mp, INF);        cin >> n >> m >> k;        for (int i = 1; i <= n; i++) cin >> popu[i];        for (int i = 1; i <= m; i++) {            scanf("%d%d%d", &u, &v, &w);            mp[u][v] = mp[v][u] = min(w, mp[u][v]);        }        ans = 0;        int status = 1 << n;        for (int i = status - 1; i >= 1; i--) {            if (!(i & 1)) continue;             Kruskal(i, n, k);        }        cout << ans << endl;    }}
0 0