UVA

来源:互联网 发布:英语网络新兴词汇 编辑:程序博客网 时间:2024/06/14 12:48

点击打开题目链接



题目大意:给出n个点的坐标,连边的费用为两端点的欧几里得距离。给出q种套餐,购买某种套餐花费Ci,该套餐中所有点将连通,求最小花费。

思路:读完题后知道是kruskal最短路问题,但如果枚举所有套餐,又要给所有边排序,又要kruskal,规模太大肯定超时。

所以需要优化:先kruskal求一次得到n-1条边,然后从这n-1条边中用二进制枚举子集的方法枚举套餐

附上AC代码:

#include<cstdio>#include<algorithm>using namespace std;const int maxn = 1000+5;typedef long long ll;int T;//T组样例int n, q;//共n个点,q个套餐int city_num[8], pack_spend[8];//city_num[]:单个套餐内的点数目 pack_spend[]:套餐花费int pack_city[8][maxn];//pack_city[]:单个套餐内点的集合int x[maxn], y[maxn];//坐标int par[maxn];//根节点int m, cnt;struct edges {int fr, to, val;bool operator <(const edges & e){return val < e.val;}}_edge[maxn*maxn],edge[maxn];////初始化void init(){for (int i = 0; i <= n; i++)par[i] = i;}//找根节点int find(int x){return x == par[x] ? x : par[x] = find(par[x]);}//计算欧几里得距离int dis(int a, int b){return (x[a] - x[b])*(x[a] - x[b]) + (y[a] - y[b])*(y[a] - y[b]);}//kruskalll kruskal(){ll ans = 0;for (int i = 1; i < n; i++){int dx = find(edge[i].fr);int dy = find(edge[i].to);if (dx != dy){par[dx] = dy;ans += edge[i].val;}}return ans;}int main(){//ios::sync_with_stdio(false);scanf("%d",&T);while(T--){    cnt = m = 0;//readscanf("%d %d", &n, &q);for (int i = 0; i < q; i++){scanf("%d%d", & city_num[i], & pack_spend[i]);for (int j = 1; j <= city_num[i]; j++)scanf("%d", & pack_city[i][j]);}for (int i = 1; i <= n; i++)scanf("%d%d", &x[i], &y[i]);//solveinit();for (int i = 1; i <= n; i++){for (int j = i + 1; j <= n; j++){_edge[++cnt].fr = i;_edge[cnt].to = j;_edge[cnt].val = dis(i, j);}}//全体点的kruskalll ans = 0;sort(_edge + 1, _edge + cnt + 1);for (int i = 1; i <= cnt; i++){int dx = find(_edge[i].fr);int dy = find(_edge[i].to);if (dx != dy){par[dx] = dy;ans += _edge[i].val;edge[++m] = _edge[i];}}//套餐的二进制枚举for (int t = 0; t < (1 << q); t++){ll anxd = 0;init();for (int i = 0; i < q; i++){if (t&(1 << i)){anxd += pack_spend[i];for (int j = 2; j <= city_num[i]; j++)par[find(pack_city[i][j-1])] = find(pack_city[i][j]);}}anxd += kruskal();ans = min(ans, anxd);}printf("%lld\n", ans);if (T)printf("\n");}//system("pause");return 0;}