最小樹形圖


每個點貪心找最小的前驅選上,然后分情況:
如果形成一棵樹,那么算法結束;
否則對該圖縮點,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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM