链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2121
题目:
3 1 0 1 1 4 4 0 1 10 0 2 10 1 3 20 2 3 30
impossible 40 0
分析与总结:
不定根最小树形图问题,解决方法是设计一个“虚拟新根点”,这个从这个结点出发可以到达所有点,并且权值是一个很大的值(比所有权值之和大),然后找这个跟结点是否有最小树形图。
而求出真正的跟结点的方法很巧妙, 利用边的位置与虚拟结点的关系。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> using namespace std; const int VN = 1005; const int INF = 0x7fffffff; int ans_root; template<typename Type> class Directed_MST{ public: void init(int _n){ n=_n+1; size=0; ans=0; } void insert(int u, int v, Type _w){ E[size++].set(u,v,_w); } Type directed_mst(int root){ while(true){ // 1.找最小的前驱边 for(int i=1; i<n; ++i) in[i]=INF; for(int i=0; i<size; ++i){ int u=E[i].u, v=E[i].v; if(E[i].w < in[v] && u!=v){ pre[v] = u; in[v] = E[i].w; if(u==root){ ans_root = i; // 保存的是边的位置i,而不是v } } } for(int i=1; i<n; ++i)if(i!=root){ if(in[i]==INF) return -1; } // 2.找环 int MXid = 1; in[root] = 0; memset(id, -1, sizeof(id)); memset(vis, -1, sizeof(id)); for(int i=1; i<n; ++i){ ans += in[i]; int v = i; while(vis[v]!=i && id[v]==-1 && v!=root){ vis[v] = i; v = pre[v]; } if(v!=root && id[v]==-1){ for(int u=pre[v]; u!=v; u=pre[u]){ id[u] = MXid; } id[v] = MXid++; } } if(MXid==1) break; //无环 for(int i=1; i<n; ++i) if(id[i]==-1) id[i] = MXid++; // 3.缩点,重新标记 for(int i=0; i<size; ++i){ int u=E[i].u, v=E[i].v; E[i].u = id[u]; E[i].v = id[v]; if(E[i].u!=E[i].v) E[i].w -= in[v]; } n = MXid; root = id[root]; } return ans; } private: struct Edge{ int u,v; Type w; void set(int _u,int _v,Type _w){ u=_u,v=_v,w=_w; } }E[VN*VN/2]; Type ans; // 所求答案 Type in[VN]; int n; // 结点个数 int size; // 边的数量 int pre[VN]; // 权值最小的前驱边 int id[VN]; int vis[VN]; // 是在环中还是在环外 }; Directed_MST<int>G; int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ G.init(n+1); int Max = 0; for(int i=0; i<m; ++i){ int a,b; int c; scanf("%d%d%d",&a,&b,&c); if(a==b)continue; Max += c; G.insert(a+1,b+1,c); } ++Max; // 把n+1设置为虚拟根结点 for(int i=m; i<m+n; ++i){ G.insert(n+1, i-m+1, Max); // 注意虚拟结点n+1与i的关系,当i>m之后,依次从虚拟根结点n+1出发 // 到达1,2,...,n.利用这个关系,当i>m时利用位置就可以确定m+1与其它结点的关系 // 后面要用这个关系输出根结点 } int ans = G.directed_mst(n+1); if(ans==-1 || ans-Max>=Max)puts("impossible"); else printf("%d %d\n", ans-Max, ans_root-m); puts(""); } return 0; }
—— 生命的意义,在于赋予它意义。
原创 http://blog.csdn.net/shuangde800 , By D_Double (转载请标明)