2021.12.01 朱刘算法

朱刘算法:

https://blog.csdn.net/u011815404/article/details/85858501

https://blog.csdn.net/dajiangyou123456/article/details/105137781?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1.no_search_link

https://www.luogu.com.cn/blog/i207M/shu-xing-tu-shu-liu-suan-fa-xue-xi-bi-ji-xie-ti-bao-gao-p4716-post

tarjan搞出来的奇奇怪怪的算法:

https://www.luogu.com.cn/blog/CHiCO/solution-p4716

模板题

https://www.luogu.com.cn/problem/P4716

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=210;
const int M=1e4+10;
const int inf=2e9;
int n,m,root,id[N],val[N],vis[N],pre[N];
struct node{
	int from,to,val;
}a[M];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline int zhuLiu(){
	int ans=0;
	//ans在这里操作有点类似于反悔贪心的意思 
	while(true){
		//找到最小入边 
		for(int i=1;i<=n;i++)val[i]=inf;
		for(int i=1;i<=m;i++){
			int u=a[i].from,v=a[i].to;
			if(u!=v&&val[v]>a[i].val)val[v]=a[i].val,pre[v]=u;
		}
		//如果有独立的点就不可能形成树形图 
		for(int i=1;i<=n;i++)if(i!=root&&val[i]==inf)return -1;
		//找环,计算环的个数 
		int cnt=0;
		for(int i=1;i<=n;i++)vis[i]=id[i]=0;
		for(int i=1;i<=n;i++){
			if(i==root)continue;
			ans+=val[i];
			//如果i所在的圈之前已经被选过了,现在又选就相当于释放了一条边,变成个不是圈的东西 
			int v=i;
			//找环 
			while(vis[v]!=i&&!id[v]&&v!=root)vis[v]=i,v=pre[v];
			//如果在环上并且没有连到root,染色 
			if(!id[v]&&v!=root){
				id[v]=++cnt;
				for(int u=pre[v];u!=v;u=pre[u])id[u]=cnt;
			}
		}
		//没有环,返回 
		if(cnt==0)break;
		//有环,把剩下没有染色的不在环上的节点染色 
		for(int i=1;i<=n;i++)if(!id[i])id[i]=++cnt;
		//更新边的起点、终点、边权 
		for(int i=1;i<=m;i++){
			int u=a[i].from,v=a[i].to;
			a[i].from=id[u];a[i].to=id[v];
			if(a[i].from!=a[i].to)a[i].val-=val[v];
		}
		//更新root和这轮朱刘算法过后结点的个数,毕竟缩点了 
		root=id[root];
		n=cnt;
	}
	return ans;
}

int main(){
	n=read();m=read();root=read();
	for(int i=1;i<=m;i++){
		a[i].from=read();a[i].to=read();a[i].val=read();
	}
	cout<<zhuLiu();
	return 0;
}

练习题:

https://www.luogu.com.cn/problem/P2792

//只要买了就能享受优惠价
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=55;
const int inf=2e9;
int n,m,k,root,num[N],id[N],vis[N],pre[N],true_id[N];
double minn[N],price[N],ans,val[N];
struct node{
	int from,to;
	double val;
}a[N*N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline double zhuLiu(){
	while(true){
		for(int i=1;i<=n;i++)val[i]=inf;
		for(int i=1;i<=m;i++){
			int u=a[i].from,v=a[i].to;
			if(u!=v&&val[v]>a[i].val)val[v]=a[i].val,pre[v]=u;
		}
		for(int i=1;i<=n;i++)if(i!=root&&val[i]==inf)return -1;
		int cnt=0;
		for(int i=1;i<=n;i++)id[i]=vis[i]=0;
		for(int i=1;i<=n;i++){
			if(i==root)continue;
			ans+=val[i];
			int v=i;
			while(vis[v]!=i&&!id[v]&&v!=root)vis[v]=i,v=pre[v];
			if(!id[v]&&v!=root){
				id[v]=++cnt;
				for(int u=pre[v];u!=v;u=pre[u])id[u]=cnt;
			}
		}
		if(cnt==0)break;
		for(int i=1;i<=n;i++)if(!id[i])id[i]=++cnt;
		for(int i=1;i<=m;i++){
			int u=a[i].from,v=a[i].to;
			a[i].from=id[u];a[i].to=id[v];
			if(a[i].from!=a[i].to)a[i].val-=val[v];
		}
		n=cnt;
		root=id[root];
	}
	return ans;
} 

int main(){
	n=read();
	int top=1;
	root=1;
	for(int i=1;i<=n;i++){
		minn[i]=inf;
		cin>>price[i];
		num[i]=read();
		if(!num[i])continue;
		true_id[i]=++top;
		minn[i]=min(minn[i],price[i]);
		a[++m]={1,top,price[i]};
	}
	k=read();
	for(int i=1;i<=k;i++){
		int u,v;
		double w;
		u=read();v=read();cin>>w;
		if(!true_id[u]||!true_id[v])continue;
		minn[v]=min(minn[v],w);
		a[++m]={true_id[u],true_id[v],w};
	}
	for(int i=1;i<=n;i++)if(num[i]>1)ans+=(num[i]-1)*minn[i];
	n=top;
	printf("%.2lf",zhuLiu());
	return 0;
}
 posted on 2021-12-01 11:31  eleveni  阅读(31)  评论(0)    收藏  举报