uva 1151最小生成树

先求一次最小生成树,可以排除n*(n*1)/2-(n-1)条边,每次利用二进制法枚举套餐的选择,套餐中的点直接处理,如果两个套餐有公共点直接合并,他们一定连通,然后枚举第一步最小生成树得到的n-1条边就能够得到在购买当前套餐下能得到的最优解。

注意:修建两点之间的道路的费用是欧几里德距离的平方。

AC代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=1000+5;
const int inf=1<<30;
int n,q,cnt;
int px[maxn],py[maxn],p[maxn],vis[maxn];
struct node{
	int a,b;
	int w;
	bool operator <(const node &p)const {
		return w<p.w;
	}
}e[maxn*maxn/2],ex[maxn];
struct net{
	int cnt;
	int point[maxn];
	int w;
}c[10];
inline int find(int x){
	return p[x]==x?x:find(p[x]);
}
int kru(int h){
	int ans=0;
	for(int i=0;i<n;++i) p[i]=i;
	memset(vis,0,sizeof(vis));
	for(int i=0;i<q;++i){
		if((h>>i)&1){
			ans+=c[i].w;
			int k=c[i].point[0];
			for(int j=0;j<c[i].cnt;++j){
				if(vis[c[i].point[j]]) {
					k=find(c[i].point[j]);
					break;
				}
			}
			for(int j=0;j<c[i].cnt;++j){
				if(!vis[c[i].point[j]]) p[c[i].point[j]]=k;
				vis[c[i].point[j]]=1;
			}
		}
	}
	for(int i=0;i<n-1;++i){
		int x=find(ex[i].a), y=find(ex[i].b);
		if(x!=y){
			ans+=ex[i].w;
			p[y]=x;
		}
	}
	return ans;
}
int solve(){
	int ans=inf;
	sort(e,e+cnt);
	for(int i=0;i<n;++i) p[i]=i;
	int c2=0;
	for(int i=0;i<cnt;++i){
		int x=find(e[i].a), y=find(e[i].b);
		if(x!=y){
			p[y]=x;
			ex[c2++]=e[i];
		}
	}
	for(int i=0;i<(1<<q);++i){
		ans=min(ans,kru(i));
	}
	return ans;
}
int main(){
	int T;
	scanf("%d",&T);
	int kase=0;
	while(T--){
		if(kase++) printf("\n");
		scanf("%d%d",&n,&q);
		for(int i=0;i<q;++i){
			scanf("%d%d",&c[i].cnt,&c[i].w);
			for(int j=0;j<c[i].cnt;++j) {
				scanf("%d",&c[i].point[j]);
				c[i].point[j]--;
			}
		}
		for(int i=0;i<n;++i) scanf("%d%d",&px[i],&py[i]);
		cnt=0;
		for(int i=0;i<n;++i)
			for(int j=i+1;j<n;++j){
				e[cnt].a=i; e[cnt].b=j;
				e[cnt++].w=(px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j]);
			}
		printf("%d\n",solve());
	}
	return 0;
}

如有不当之处欢迎指出!

上一篇:C++ Builder中TOpenDialog控件的使用例子


下一篇:高效图片轮播,两个imageView实现