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
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条边的无线图, 顶点1为首都, 每个点的权值为人口数, 每条边的权值为修复此道路的花费, 让你得出花费不超过k的情况下, 以首都为起点的最小生成树所包含的最大人口数。
看了别人的博客, 想了一晚上, 算是搞懂了一些。 基本思路就是暴力搜索, 顶点数为16, 可以用int类型的每一个二进制位表示所有顶点的全部组合形式, 然后验证每一种形式的可行性,最后得出一个最大解。
#include<bits/stdc++.h>
using namespace std;
int pre[20];//并查集
struct node
{
int v;
int u;
int w;
} edge[111]; //边集
int num[20];//存每一点人口数
int k, n, m;
int vis[20];//标记出每一种组合形式
void mix(int a, int b)
{
pre[a] = b;
}
int Find(int a)
{
int t = a;
while(pre[a] != a)
{
a = pre[a];
}
while(t != a)//并查集优化, 这个循环可以去掉
{
int tt = pre[t];
pre[t] = a;
t = tt;
}
return a;
}
bool cmp(struct node a, struct node b)
{
return a.w <= b.w;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++)
{
scanf("%d", &num[i]);
}
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
}
sort(edge,edge + m, cmp);
int len = (1 << n);//将所有组合压缩到 0 - len- 1
int max_p = -1;//存最大解
for(int i = 0; i < len; i++)
{
int v_cnt = 0;//存每一种组合所包含的点数
for(int j = 0; j < n; j++)//验证第j + 1个点在第i种组合中是否要连通
{
if((1 << j) & i)//第j位存在则将j+1点标记
{
vis[j + 1] = 1;
v_cnt ++;
}
else
vis[j + 1] = 0;
}
if(!vis[1])//如果这种组合不包含首都则直接pass掉
{
continue;
}
for(int j = 1; j <= n; j++)//并查集准备
pre[j] = j;
int e_cnt = 0;//存边数量
int cost = 0;//存花费
for(int j = 0; j < m; j++)
{
int u = edge[j].u;
int v = edge[j].v;
int w = edge[j].w;
int pre_u = Find(u);
int pre_v = Find(v);
if(vis[u] && vis[v] && (pre_u != pre_v))//两点被标记且还可以合并则将其合并,边数加一
{
mix(pre_u, pre_v);
e_cnt++;
cost += w;
}
if(e_cnt == v_cnt - 1)
break;
}
int pop_cnt = 0;
if(e_cnt == v_cnt - 1 && cost <= k)//满足最小生成树条件且花费不大于k即为一课可行最小生成树,找出各个可行最小生成树的最大人口数
{
for(int j = 1; j <= n; j++)
{
if(vis[j])
{
pop_cnt += num[j];
}
}
max_p = max(pop_cnt, max_p);
}
}
printf("%d\n", max_p);
}
return 0;