• 最小树形图


    每个点贪心找最小的前驱选上,然后分情况:
    如果形成一棵树,那么算法结束;
    否则对该图缩点,scc之间的边的权值赋值成 用这条边替代原来终点的前驱的代价 的权值,表示换去一条环边,然后做最小树形图即可。
    每轮至少缩去一个点,复杂度 (O(n^2+nm))

    void tarjan(int u)
    {
    	dfn[u]=low[u]=++ord;
    	stk[++top]=u;
    	ins[u]=1;
    	int v=nxt[u];
    	if(!dfn[v])
    		tarjan(v),low[u]=min(low[u],low[v]);
    	else if(ins[v])
    		low[u]=min(low[u],dfn[v]);
    	if(dfn[u]==low[u])
    	{
    		++cnt;
    		for(int x=stk[top];;x=stk[top])
    		{
    			--top;
    			scc[x]=cnt;
    			ins[x]=0;
    			if(x==u)
    				break;
    		}
    	}
    }
    
    int work(int n,vector<edge>e,int root)
    {
    	int ans=0;
    	while(1)
    	{
    		vector<int>d(n+1,1e9);
    		for(int i=1; i<=n; i++)
    			nxt[i]=scc[i]=dfn[i]=low[i]=ins[i]=0;
    		for(auto &k:e)
    			if(k.u!=k.v&&k.w<d[k.v])
    				d[k.v]=k.w,nxt[k.v]=k.u;
    		nxt[root]=root;
    		d[root]=0;
    		for(int i=1; i<=n; i++)
    		{
    			if(!nxt[i])
    				return -1;
    			ans+=d[i];
    		}
    		top=ord=cnt=0;
    		for(int i=1; i<=n; i++)
    			if(!dfn[i])
    				tarjan(i);
    		if(cnt==n)
    			break;
    		vector<edge> ne;
    		for(auto &k:e)
    			if(scc[k.u]!=scc[k.v])
    				ne.push_back((edge){scc[k.u],scc[k.v],k.w-d[k.v]});
    		e=ne; n=cnt; root=scc[root];
    	}
    	return ans;
    }
    
  • 相关阅读:
    第八周课程总结&实验报告(六)
    第七周课程总结&实验报告(五)
    第六周实验总结&学习总结
    关于我
    各种公告

    笔记 综合
    多项式全家桶
    FFT,NTT 笔记
    省选复习
  • 原文地址:https://www.cnblogs.com/bestwyj/p/12229921.html
Copyright © 2020-2023  润新知