[HDU 2121]Ice_cream’s world II[无定根的最小树形图]
2015-10-30 23:13
441 查看
题目链接:[HDU 2121]Ice_cream’s world II[无定根的最小树形图]
题意分析:
选择一个点作为根节点形成一个最小树形图,根节点下标尽量小。
解题思路:
虚拟出一个根节点,让它和每个点构成的边权值为 图中所有边权值之和+1 ;那么最终结果就是,如果所得图权值大于等于上值的两倍,那么不存在(从虚点连了两条边以上),否则答案就等于所得结果减去上值(即减去多出来的那一条虚边)。
剩下的问题在于多个答案下,最小的根节点怎么求。由于朱刘算法在选择最小权值入边的时候,是根据边的标号从小往大遍历的,那么我们可以从小到大添加虚边,那么第一个被选入的虚边所连的那个入点就是答案了。
个人感受:
6得不行啊这样子做。Orz
具体代码如下:
题意分析:
选择一个点作为根节点形成一个最小树形图,根节点下标尽量小。
解题思路:
虚拟出一个根节点,让它和每个点构成的边权值为 图中所有边权值之和+1 ;那么最终结果就是,如果所得图权值大于等于上值的两倍,那么不存在(从虚点连了两条边以上),否则答案就等于所得结果减去上值(即减去多出来的那一条虚边)。
剩下的问题在于多个答案下,最小的根节点怎么求。由于朱刘算法在选择最小权值入边的时候,是根据边的标号从小往大遍历的,那么我们可以从小到大添加虚边,那么第一个被选入的虚边所连的那个入点就是答案了。
个人感受:
6得不行啊这样子做。Orz
具体代码如下:
#include<cmath> #include<cstdio> #include<cstring> using namespace std; const int INF = 0x7f7f7f7f; const int MAXN = 1e3 + 111; struct Edge{ int u, v, w; }edge[20100]; int newid[MAXN], pre[MAXN], vis[MAXN], ecnt, in[MAXN], minRt; void add_edge(int u, int v, int w) { edge[ecnt].u = u; edge[ecnt].v = v; edge[ecnt++].w = w; } int zhuLiu(int rt, int V) { int ret = 0; while (1) { for (int i = 0; i <= V; ++i) in[i] = INF; for (int i = 0; i < ecnt; ++i) { int u = edge[i].u, v = edge[i].v; if (u != v && in[v] > edge[i].w) { in[v] = edge[i].w, pre[v] = u; if (u == rt) minRt = i; // 因为在整个过程中,结点编号会变,但是边编号不会变。 } } // 本题有了虚边之后最小树形图一定存在,所以就不判断不存在的情况了XD int cnt = 0; memset(newid, -1, sizeof newid); memset(vis, -1, sizeof vis); in[rt] = 0; for (int i = 0; i <= V; ++i) { ret += in[i]; int v = i; while (vis[v] != i && newid[v] == -1 && v != rt) { vis[v] = i; v = pre[v]; } if (v != rt && newid[v] == -1) { for (int u = pre[v]; u != v; u = pre[u]) newid[u] = cnt; newid[v] = cnt++; } } if (cnt == 0) break; for (int i = 0; i <= V; ++i) if (newid[i] == -1) newid[i] = cnt++; for (int i = 0; i < ecnt; ++i) { int u = edge[i].u, v = edge[i].v; edge[i].u = newid[u]; edge[i].v = newid[v]; if (newid[u] != newid[v]) edge[i].w -= in[v]; } V = cnt - 1; rt = newid[rt]; } return ret; } int main() { int n, m, u, v, w; while (~scanf("%d%d", &n, &m)) { ecnt = 0; int mxVal = 0; for (int i = 0; i < m; ++i) { scanf("%d%d%d", &u, &v, &w); add_edge(u, v, w); mxVal += w; } ++mxVal; // 在原图建立之后再对虚源点连边,保证遍历从小开始,同时保证虚边都在m条边之后建立 for (int i = 0; i < n; ++i) add_edge(n, i, mxVal); int ans = zhuLiu(n, n); if (ans >= 2 * mxVal) printf("impossible\n\n"); else { printf("%d %d\n\n", ans - mxVal, minRt - m); } } return 0; }
相关文章推荐
- 希尔排序和归并排序
- C#未捕获异常处理方法
- nodejs初学到express框架使用
- UI中自定制cell--2
- 文章标题
- 项目冲刺--第二天
- 1042. 字符统计(20)
- 企业日志分析之linux系统history收集展示
- 爬爬爬之路:OC语言(五) 字典 集合常用方法介绍
- 1041. 考试座位号(15)
- 冒泡算法
- 调试驱动
- 修改~/.bashrc文件 改编终端颜色
- 字符转ASCLL码输出
- 磁盘驱动器
- 前端布局革命史
- pandas小记:pandas基本设置
- pandas小记:pandas基本设置
- sleep()、wait()、yield()、join()方法 解析
- 第二百一十一天 how can i 坚持