zoukankan      html  css  js  c++  java
  • HDU 2121 Ice_cream’s world II 不定根最小树形图

    题目链接:

    题目

    Ice_cream’s world II
    Time Limit: 3000/1000 MS (Java/Others)
    Memory Limit: 32768/32768 K (Java/Others)

    问题描述

    After awarded lands to ACMers, the queen want to choose a city be her capital. This is an important event in ice_cream world, and it also a very difficult problem, because the world have N cities and M roads, every road was directed. Wiskey is a chief engineer in ice_cream world. The queen asked Wiskey must find a suitable location to establish the capital, beautify the roads which let capital can visit each city and the project’s cost as less as better. If Wiskey can’t fulfill the queen’s require, he will be punishing.

    输入

    Every case have two integers N and M (N<=1000, M<=10000), the cities numbered 0…N-1, following M lines, each line contain three integers S, T and C, meaning from S to T have a road will cost C.

    输出

    If no location satisfy the queen’s require, you must be output “impossible”, otherwise, print the minimum cost in this project and suitable city’s number. May be exist many suitable cities, choose the minimum number city. After every case print one blank.

    样例

    input
    3 1
    0 1 1

    4 4
    0 1 10
    0 2 10
    1 3 20
    2 3 30

    output
    impossible

    40 0

    题意

    不固定根最小树形图,并且多解时,输出根编号最小的解

    题解

    加一个虚根,与所有的点连接单向边,权值都为"所有边权和+1"。加这额外的n条边时,按顶点编号从小到大加。然后跑朱刘算法。
    (为什么要所有权值+1呢?因为最后如果答案>=2*(所有边权和+1),就说明额外加的边用了不只一条,也就是根本无解的!)

    代码

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    const int maxn = 1111;
    const int maxm = 20101;
    const int INF = 0x7fffffff;
    
    struct Edge {
    	int u, v, w;
    	Edge(int u,int v,int w):u(u),v(v),w(w){}
    	Edge() {}
    }egs[maxm];
    int N, M;
    
    int pos;
    int in[maxn],id[maxn], vis[maxn], pre[maxn];
    int Directed_MST(int rt,int n,int m) {
    	int ret = 0;
    	while (1) {
    		//求最小入度边
    		for (int i = 0; i < n; i++) in[i] = INF;
    		for (int i = 0; i < m; i++) {
    			Edge& e = egs[i];
    			if (e.w < in[e.v] && e.u != e.v) {
    				//如果存在多解的话,那么那几个解一定在一个环上,因为以任意一个为根,都能到达其他点且使总权值最小。
    				//既然在环上最后就一定会缩成同一个点,虚根与它们的边就变成平行边了!由于我们额外的边是按节点编号从大到小排的,那么我们就只会记录编号最小的那个点了。
    				//这里不能记录pos=e.v,因为缩点之后e.v改变了
    				if (e.u == rt) pos = i;  //这里rt就是须根了!!!缩点之后不会是N的!!!
    				in[e.v] = e.w;
    				pre[e.v] = e.u;
    			}
    		}
    		for (int i = 0; i < n; i++) {
    			if (i!=rt&&in[i] == INF) return -1;
    		}
    		int tot = 0;
    		memset(id, -1, sizeof(id));
    		memset(vis, -1, sizeof(vis));
    		in[rt] = 0;
    		//找环,缩点
    		for (int i = 0; i < n; i++) {
    			ret += in[i];
    			int v = i;
    			while (vis[v] != i&&id[v] == -1 && v != rt) {
    				vis[v] = i;
    				v = pre[v];
    			}
    			if (id[v] == -1 && v != rt) {
    				for (int u = pre[v]; u != v; u = pre[u]) {
    					id[u] = tot;
    				}
    				id[v] = tot++;
    			}
    		}
    		//没有环
    		if (tot == 0) break;
    		for (int i = 0; i < n; i++) {
    			if (id[i] == -1) id[i] = tot++;
    		}
    		//更新到环的距离
    		for (int i = 0; i < m; i++) {
    			Edge& e = egs[i];
    			int v = e.v;//这个v要留下来!
    			e.u = id[e.u],e.v = id[e.v];
    			if (e.u != e.v) {
    				e.w -= in[v];
    			}
    		}
    		n = tot;
    		rt = id[rt];
    	}
    	return ret;
    }
    
    int main() {
    	while (scanf("%d%d", &N, &M) == 2 && N) {
    		int sum = 0;
    		for (int i = 0; i < M; i++) {
    			int u, v, w;
    			scanf("%d%d%d", &u, &v, &w);
    			sum += w;
    			egs[i] = Edge(u, v, w);
    		}
    		sum++;
    		for (int i = 0; i < N; i++) {
    			egs[M + i] = Edge(N, i, sum);
    		}
    		int ans = Directed_MST(N, N + 1, N+M);
    		if (ans == -1 || ans >= sum * 2) {
    			puts("impossible");
    		}
    		else {
    			printf("%d %d
    ", ans - sum, pos - M);
    		}
    		puts("");
    	}
    	return 0;
    }
  • 相关阅读:
    Java总结篇系列:Java泛型
    视图、索引、存储过程优缺点
    SQL之case when then用法
    oracle数据库表的导入导出cmd命令大全
    ORA-01652:无法通过128(在表空间temp中)扩展temp段 解决方法
    如何查看一个数据文件是否是自动扩展
    ora-01652无法通过128(在表空间temp中)扩展temp段
    解决ora-01652无法通过128(在temp表空间中)扩展temp段的过程
    Java中的JDBC基础
    Java中的Property类
  • 原文地址:https://www.cnblogs.com/fenice/p/5642152.html
Copyright © 2011-2022 走看看