当前位置: 代码迷 >> 综合 >> UVA - 11183 Teen Girl Squad(最小树形图)
  详细解决方案

UVA - 11183 Teen Girl Squad(最小树形图)

热度:16   发布时间:2023-12-17 02:47:22.0

给你T组样例,n个点,m条边,问你能不能做出一个图,使得从0点出发到所有点的总权值最小。

这是树形图的模板题,只要学完原理就很容易看懂代码https://blog.csdn.net/qq_38367681/article/details/81299822;代码如下

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <string>using namespace std;const int inf = 2e9;
const int maxn = 1005;
const int maxm = 40050;int n, m;//顶点数,边数
int in[maxn];//in[u]记录当前图中指向u结点的所有边权中最小的那条边权
int pre[maxn];//pre[u]记录最小边权对应的父亲结点
int used[maxn], id[maxn];//used是访问标记数组,id[u]是计算出u在下一次的新图中的编号struct Edge {int from, to;int dist;Edge(int f = 0, int t = 0, int d = 0) :from(f), to(t), dist(d) {}
}edges[maxm];//边集int direct_mst(int root, int V, int E) {//三个参数分别是根结点,顶点数量,边数量int ans = 0;while (1) {//为每个非根结点选出最小入边for (int i = 0; i < V; ++i) in[i] = inf;for (int i = 0; i < E; ++i) {int u = edges[i].from;int v = edges[i].to;if (in[v] > edges[i].dist && u != v) {in[v] = edges[i].dist;pre[v] = u;}}//判断连通性,如有不可达结点说明无解for (int i = 0; i < V; ++i) {if (i == root) continue;if (inf == in[i]) return -1;}//判断有向环是否存在,存在有向环就缩圈int cnt = 0;//生成新图的结点编号memset(id, -1, sizeof(id));//id[u]==-1表示结点u还不属于任何一个自环memset(used, -1, sizeof(used));in[root] = 0;for (int i = 0; i < V; ++i) {ans += in[i];int v = i;while (used[v] != i && id[v] == -1 && v != root) {//每个结点不断向上寻找父亲结点,要么找到根结点,要么形成一个自环used[v] = i;v = pre[v];}if (v != root && id[v] == -1) {//找到了自环,进行缩点,更新id数组for (int u = pre[v]; u != v; u = pre[u]) id[u] = cnt;id[v] = cnt++;}}if (0 == cnt) break;//没有自环说明已经求出最终结果//建立新图for (int i = 0; i < V; i++)if (id[i] == -1) id[i] = cnt++;//先把不在自环中的点的编号更新for (int i = 0; i < E; i++) {int u = edges[i].from;int v = edges[i].to;edges[i].from = id[u];edges[i].to = id[v];if (id[u] != id[v]) edges[i].dist -= in[v];//这里id[u] != id[v]说明edges[i]这条边原来不在有向环中,//如果这条边指向了有向环,那么它的边权就要减少in[v]等价于整个环的边权减去in[v]//而如果没有指向有向环,说明它与这个有向环毫无关系,那么在之前的寻找自环缩点过//程中已经把这条边的权值加上了,所以这里避免重复计算让这条边的权值减小in[v]变为0}V = cnt;root = id[root];}return ans;
}int main()
{int T, t = 0;cin >> T;while(T--) {int n, m;cin >> n >> m;for(int i = 0; i < m; i++) {cin >> edges[i].from >> edges[i].to >> edges[i].dist;if(edges[i].from == edges[i].to)edges[i].dist = inf;}int ans = direct_mst(0, n, m);printf("Case #%d: ", ++t);if(ans == -1)cout << "Possums!" << endl;elsecout << ans << endl;}
}