poj 3164 Command Network

題目大意:給你n個點,m條可選的有向邊,要你選擇n-1條邊使得一號點可以到達所有點且邊權最小,求最小的邊權是多少 n<=100 m<=10000


這題就是一個裸的最小樹形圖(朱劉算法),不多說了,直接貼代碼

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define sqr(x) ((x)*(x))
using namespace std;
const int maxn=110,maxm=10011;
const double INF=1e9;
struct Tedge{int x,y; double w;}e[maxm];
int n,m; double x[maxn],y[maxn];
double dis(int a,int b){return sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b]));}
void init(){
	for (int i=1;i<=n;++i) scanf("%lf%lf",x+i,y+i);
	for (int i=1;i<=m;++i){
		scanf("%d%d",&e[i].x,&e[i].y); e[i].w=dis(e[i].x,e[i].y);
		if (e[i].x==e[i].y) --i,--m;
	}
}
double in[maxn]; int pre[maxn],vis[maxn],be[maxn];
void work(){
	int V=n,E=m,root=1; double ans=0;
	while (1){
		for (int i=1;i<=V;++i) in[i]=INF,pre[i]=0;
		for (int i=1;i<=E;++i)
			if (e[i].x!=e[i].y && in[e[i].y]>e[i].w) in[e[i].y]=e[i].w,pre[e[i].y]=e[i].x;
		for (int i=1;i<=V;++i) if (i!=root && !pre[i]) return puts("poor snoopy"),void();
		int cnt=0; for (int i=1;i<=V;++i) vis[i]=be[i]=0; in[root]=0;
		for (int i=1;i<=V;++i){
			ans+=in[i]; int tmp=i,t;
			while (vis[tmp]!=i && !be[tmp] && tmp!=root) vis[tmp]=i,tmp=pre[tmp];
			if (tmp!=root && !be[tmp])
 				for (be[tmp]=++cnt,t=pre[tmp];t!=tmp;t=pre[t]) be[t]=cnt;
		}
		if (!cnt) return printf("%.2f\n",ans),void();
		for (int i=1;i<=V;++i) if (!be[i]) be[i]=++cnt;
		for (int i=1;i<=E;++i){
			int x=e[i].x,y=e[i].y;
			if ((e[i].x=be[x])!=(e[i].y=be[y])) e[i].w-=in[y];
		}
		root=be[root]; V=cnt;
	}
}
int main(){while (scanf("%d%d",&n,&m)!=EOF) init(),work(); return 0;}



。。。上面的那個是有一定的問題的,可能會被卡到O(n^3+nm)的,下面再給出一個修改過後是嚴格O(n^2+nm)的

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define sqr(x) ((x)*(x))
using namespace std;
const int maxn=110,maxm=10011,INF=(int)1e9;
struct Tedge{int x,y; double w;}e[maxm];
int n,m; double x[maxn],y[maxn];
double dis(int a,int b){return sqrt(sqr(x[a]-x[b])+sqr(y[a]-y[b]));}
void init(){
	for (int i=1;i<=n;++i) scanf("%lf%lf",x+i,y+i);
	for (int i=1;i<=m;++i){
		scanf("%d%d",&e[i].x,&e[i].y); e[i].w=dis(e[i].x,e[i].y);
		if (e[i].x==e[i].y) --i,--m;
	}
}
double in[maxn];int pre[maxn],be[maxn],vis[maxn];
void work(){
	int V=n,E=m,root=1; double ans=0;
	while (1){
		for (int i=1;i<=V;++i) in[i]=INF; in[root]=0; int cnt=0,ne=0;
		for (int i=1;i<=E;++i)
			if (e[i].y!=root && in[e[i].y]>e[i].w) in[e[i].y]=e[i].w,pre[e[i].y]=e[i].x;
		for (int i=1;i<=V;++i) if (in[i]==INF) return puts("poor snoopy"),void();
		for (int i=1;i<=V;++i) be[i]=vis[i]=0; vis[root]=V+1;
		for (int i=1;i<=V;++i){
			ans+=in[i]; int tmp=i,t; while (!vis[tmp]) vis[tmp]=i,tmp=pre[tmp];
			if (vis[tmp]==i) for (be[tmp]=++cnt,t=pre[tmp];t!=tmp;t=pre[t]) be[t]=cnt;
		}
		if (!cnt) return printf("%.2f\n",ans),void();
		for (int i=1;i<=V;++i) if (!be[i]) be[i]=++cnt;
		for (int i=1;i<=E;++i){
			int x=e[i].x,y=e[i].y;
			if (be[x]!=be[y]) e[++ne].x=be[x],e[ne].y=be[y],e[ne].w=e[i].w-in[y];
		}
		E=ne; V=cnt; root=be[root];
	}
}
int main(){while (scanf("%d%d",&n,&m)!=EOF) init(),work(); return 0;}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章