hdu2121-Ice_cream’s world II
2017-04-17 20:11
344 查看
给出一个有向图,求最小树形图和它的最小的根。
这是一个不定根问题,经典解决方法是添加一个超级根,向每个点连一条长度大于所有边权和的边,设它为\(sum\),然后以超级根为根求最小树形图。如果最后最小树形图的答案超过了\(2sum\),那么就说明超级根至少连出去两条边,即原图不连通。如果原图连通,那么把\(sum\)减掉即可。
关键在于如何求最小的根。可以发现,如果我们从小到大把超级根到所有点的边加进去,然后在算法过程中从小到大遍历边,如果有多个\(in\)最小且从root过来的,那么我们会找到最小的那个。但是缩点怎么办呢?朱刘算法的这种写法的一个很大的好处就是保留了所有的点,只是改了它们的id,所以我们可以以边为关键搜索,如果找到第\(i\)条边为\((root,v,w)\),它是最小的,那么就把最小根更新为\(i\),那么最终的最小根就是\(i-m\),其中\(m\)为原图上的边数。非常巧妙!
代码的几个需要注意的地方:
找环的时候不能把已经有id的点再给一次id
在内部找环的时候从上一个开始找
只有当原来的边的两个点不在同一个环中才能减它的边权
前面在处理in的时候当\(u=v\)的时候直接跳过这条边
现在这个写法中的无环条件为col=1
分析
这个题又写了一晚上~我之前的朱刘算法写法是我乱想的,只有那道题可以过……所以去找了一份代码来看,发现我的写法超级麻烦啊,所以就学习了一下那种写法,非常漂亮,但是有一些判断要考虑。这是一个不定根问题,经典解决方法是添加一个超级根,向每个点连一条长度大于所有边权和的边,设它为\(sum\),然后以超级根为根求最小树形图。如果最后最小树形图的答案超过了\(2sum\),那么就说明超级根至少连出去两条边,即原图不连通。如果原图连通,那么把\(sum\)减掉即可。
关键在于如何求最小的根。可以发现,如果我们从小到大把超级根到所有点的边加进去,然后在算法过程中从小到大遍历边,如果有多个\(in\)最小且从root过来的,那么我们会找到最小的那个。但是缩点怎么办呢?朱刘算法的这种写法的一个很大的好处就是保留了所有的点,只是改了它们的id,所以我们可以以边为关键搜索,如果找到第\(i\)条边为\((root,v,w)\),它是最小的,那么就把最小根更新为\(i\),那么最终的最小根就是\(i-m\),其中\(m\)为原图上的边数。非常巧妙!
代码
为什么全改giant还比只改用到的快200ms啊。代码的几个需要注意的地方:
找环的时候不能把已经有id的点再给一次id
在内部找环的时候从上一个开始找
只有当原来的边的两个点不在同一个环中才能减它的边权
前面在处理in的时候当\(u=v\)的时候直接跳过这条边
现在这个写法中的无环条件为col=1
#include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; typedef long long giant; giant read() { giant x=0,f=1; char c=getchar(); for (;!isdigit(c);c=getchar()) if (c=='-') f=-1; for (;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } const giant maxn=2e3+10; const giant maxm=4e4+10; const giant inf=1e8+7; struct edge { giant u,v,w,nxt; }; struct graph { edge e[maxm]; giant h[maxn],tot,in[maxn],from[maxn],id[maxn],tic[maxn],n,real,vis[maxn]; void clear(giant _n) { memset(h,0,sizeof h),tot=0,n=_n; } void add(giant u,giant v,giant w) { e[++tot]=(edge){u,v,w,h[u]}; h[u]=tot; } giant MTG(giant root) { giant ret=0; while (true) { fill(in+1,in+n+1,inf); memset(id,0,sizeof id); memset(from,0,sizeof from); memset(vis,0,sizeof vis); for (giant i=1;i<=tot;++i) if (e[i].u!=e[i].v && in[e[i].v]>e[i].w) { in[e[i].v]=e[i].w,from[e[i].v]=e[i].u; if (e[i].u==root) real=i; } giant col=1,j; for (giant i=1;i<=n;++i) if (i!=root) { ret+=in[i]; for (j=i;j!=root && !id[j];j=from[j]) if (vis[j]!=i) vis[j]=i; else break; if (j!=root && !id[j]) { for (giant k=from[j];k!=j;k=from[k]) id[k]=col; id[j]=col++; } } if (col==1) break; for (giant i=1;i<=n;++i) if (!id[i]) id[i]=col++; for (giant i=1;i<=tot;++i) { giant 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]; } root=id[root],n=col-1; } return ret; } } A; int main() { #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("my.out","w",stdout); #endif giant n,m; while (~scanf("%lld%lld",&n,&m)) { A.clear(n+1); giant sum=1; for (giant i=1;i<=m;++i) { giant u=read()+1,v=read()+1,w=read(); A.add(u,v,w); sum+=w; } for (giant i=1;i<=n;++i) A.add(n+1,i,sum); giant ans=A.MTG(n+1); if ((ans-=sum)>=sum) puts("impossible\n"); else printf("%lld %lld\n\n",ans,A.real-m-1); } }
相关文章推荐
- HDU2121 Ice_cream’s world II【最小树形图】【不定根】
- hdu2121 - Ice_cream’s world II(朱刘算法,不固定根)
- HDU2121 Ice_cream’s world II【最小树形图】
- hdu2121 Ice_cream’s world II (最小树形图模板)
- HDU2121:Ice_cream’s world II
- HDU2121 Ice_cream’s world II 【最小树形图】+【不定根】
- hdu2121---Ice_cream’s world II
- HDU2121-Ice_cream’s world II(最小树形图)
- kuangbin专题八 HDU2121 Ice_cream’s world II(不定根的最小树形图)
- HDU - 2121-Ice_cream’s world II-无根最小树形图
- HDU 2121 Ice_cream’s world II
- HDU 2121 Ice_cream’s world II(不定根最小树形图)
- HDU-2121-Ice_cream’s world II
- Ice_cream’s world II - HDU 2121 朱刘算法
- hdu 2121 Ice_cream’s world II(最小树形图,不定根)
- HDU 2121 Ice_cream’s world II(最小树形图)
- [HDU 2121] Ice_cream’s world II 最小树形图
- 2017-03-18 Ice_cream’s world II
- Command Network POJ - 3164 + Ice_cream’s world II HDU - 2121
- HDU 2121 Ice_cream’s world II(不定根最小树形图)