朱刘算法

求最小树形图的算法。
非常易懂(暴力),贪心->找环->缩点->贪心。。。。
通过减法表示以一条边代替另一条边的思想很nb,不愧是大天朝的算法
数字打标记+for循环找基环树的环,学习了。
O ( n m ) O(nm) O(nm)

模板:

#include
#define maxn 105
#define maxm 10005
using namespace std;

int n,m,r;
int x[maxm],y[maxm],cst[maxm];
int vis[maxn];
int inv[maxn],F[maxn],inl[maxn];
inline int Find(int now){ return (F[now]==0 || F[now]==now) ? now : F[now] = Find(F[now]); }

int main()
{
	
	//freopen("1.in","r",stdin);
	
	scanf("%d%d%d",&n,&m,&r);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&x[i],&y[i],&cst[i]);
		
	int ans = 0;
	for(bool flag;;)
	{
		flag=0;
		for(int i=1;i<=n;i++) inl[i]=-1,vis[i]=0,inv[i]=0;
		for(int i=1;i<=m;i++)
			if(y[i]!=x[i] && y[i]!=r && (inl[y[i]]==-1 || cst[inl[y[i]]] > cst[i]))
				inl[y[i]] = i;
		for(int i=1;i<=n;i++) if(Find(i) == i && inl[i] == -1 && i!=r){ puts("-1");return 0; }
		for(int i=1,j;i<=n;i++)
			if(inl[i]!=-1 && !vis[i])
			{
				j = 0;
				for(j=i;!vis[j];j=x[inl[j]])
				{
					vis[j] = i;
					if(inl[j] == -1){ j = -1; break; }
 				}
				if(j!=-1 && vis[j] == i)
				{
					int cnt = 1;
					for(int k = x[inl[j]]; k^j ; k = x[inl[k]]) cnt++;
					if(cnt > 1)
					{
						flag = 1;
						for(int k = x[inl[j]] ; k^j ; k = x[inl[k]]) F[k] = j , ans += (inv[k] = cst[inl[k]]);
						ans += (inv[j] = cst[inl[j]]);
					}
				}
			}	
		if(!flag){ for(int i=1;i<=n;i++) if(inl[i]!=-1) ans += cst[inl[i]];break; }
		for(int i=1;i<=m;i++)
			cst[i]-=inv[y[i]] , x[i]=Find(x[i]),y[i]=Find(y[i]);
	}
	
	printf("%d\n",ans);
}

你可能感兴趣的:(DFS,图论,模板)