首页 > 代码库 > hdu 4966 GGS-DDU (最小树形图)
hdu 4966 GGS-DDU (最小树形图)
2024-07-18 16:12:27 221人阅读
比较好的讲解:http://blog.csdn.net/wsniyufang/article/details/6747392
view code//首先为除根之外的每个点选定一条入边,这条入边一定要是所有入边中最小的。//现在所有的最小 入边都选择出来了,如果这个入边集不存在有向环的话,我们//可以证明这个集合就是该图的最小树形图。这个证明并不是很难。如果存在有向//环的话,我们就要将这 个有向环所称一个人工顶点,同时改变图中边的权。假//设某点u在该环上,并设这个环中指向u的边权是in[u],那么对于每条从u出发的//边(u, i, w),在新图中连接(new, i, w)的边,其中new为新加的人工顶点; 对//于每条进入u的边(i, u, w),在新图中建立边(i, new, w-in[u])的边。为什么//入边的权要减去in[u],这个后面会解释,在这里先给出算法的步骤。然后可以//证明,新图中最小树形图的权加上旧图中被收缩 的那个环的权和,就是原图中//最小树形图的权。#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;typedef long long ll;const int INF = 1<<30;const int N = 600;const int M = N*N;int n, m, lev[55], pre[N], begid[N];int s, t, in[N<<1], p[N], vis[N], id[N];struct edge{ int u, v, w; edge() {} edge(int u, int v, int w):u(u),v(v),w(w) {}}e[M];int ecnt;inline void addedge(int u, int v, int w){ e[ecnt++] = edge(u, v, w);}int DirMst(int rt, int num)//根结点,结点数目{ int ans = 0; while(1) { for(int i=0; i<num; i++) in[i] = INF; for(int i=0; i<ecnt; i++) { int u = e[i].u, v = e[i].v; if(in[v]>e[i].w && u!=v) { in[v] = e[i].w; pre[v] = u; } } for(int i=0; i<num; i++) if(i!=rt && in[i]==INF) return -1; int cnt = 0; memset(id, -1, sizeof(id)); memset(vis, -1, sizeof(vis)); in[rt] = 0; for(int i=0; i<num; i++) { ans += in[i]; int v = i; while(vis[v]!=i && v!=rt && id[v]==-1)// 找环 { vis[v] = i; v = pre[v]; } while(v!=rt && id[v]==-1)// 有环,重新编号 { int u = pre[v]; for(;u!=v; u=pre[u]) id[u]=cnt; id[v] = cnt++; } } if(cnt==0) break; for(int i=0; i<num; i++) if(id[i]==-1) id[i]=cnt++;// 不在环内,重新编号 for(int i=0; i<ecnt; i++)// 更新环外点和环缩点后的点的距离 { int u = e[i].u, v = e[i].v; e[i].u = id[u]; e[i].v = id[v]; if(id[u]!=id[v]) e[i].w -= in[v]; } num = cnt; rt = id[rt]; } return ans;}void solve(){ ecnt = 0; for(int i=1; i<=n; i++) scanf("%d", lev+i); for(int i=1; i<=n; i++) begid[i] = begid[i-1]+lev[i-1]+1; s = 0, t = begid[n]+lev[n]+1; for(int i=1; i<=n; i++) { addedge(s, begid[i], 0); for(int j=0; j<lev[i]; j++) { addedge(begid[i]+j+1, begid[i]+j, 0); } } int c, l, d, r, w; for(int i=0; i<m; i++) { scanf("%d%d%d%d%d", &c, &l, &d, &r, &w); int u = begid[c]+l ,v = begid[d]+r; addedge(u, v, w); } printf("%d\n", DirMst(s, t));}int main(){// freopen("in.txt", "r", stdin); while(scanf("%d%d", &n, &m)>0 && (n|m)) solve(); return 0;}
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。