题意:给出n个点的坐标,现在需要让这n个点连通,可以直接在点与点之间连边,花费为两点之间欧几里得距离的平方,也可以选购套餐,套餐中所含的点是相互连通的 问最少的花费
首先想kruskal算法中,被加入的边已经是最优的了,所以当选择完套餐后,之前被丢弃的边也不会再进入最小生成树
然后就可以先求一次原图的最小生成树,保存下进入最小生成树的n-1条边
再枚举选择的套餐的情况,再求最小生成树,这里用的二进制法枚举 最后维护一个最小值就可以了
思路虽然看懂了,可是代码根本就写不出来,看着标程写的,最后还是改了那么久-- sad----------
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<algorithm> 11 using namespace std; 12 13 #define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i) 14 15 typedef long long LL; 16 const int INF = (1<<30)-1; 17 const int mod=1000000007; 18 const int maxn=1005; 19 const int maxq=8; 20 21 int n; 22 int x[maxn],y[maxn],cost[maxn]; 23 vector<int> subn[maxn]; 24 25 int p[maxn]; 26 int find(int x) {return p[x]!=x? p[x]=find(p[x]):x;} 27 28 struct edge{ 29 int u,v,d; 30 edge(int u,int v,int d):u(u),v(v),d(d) {} 31 bool operator <(const edge& rhs) const{ 32 return d<rhs.d;} 33 }; 34 35 int mst(int cnt,const vector<edge>& e,vector<edge>& used){ 36 if(cnt==1) return 0; 37 int m=e.size(); 38 int ans=0; 39 used.clear(); 40 for(int i=0;i<m;i++){ 41 int u=find(e[i].u),v=find(e[i].v); 42 int d=e[i].d; 43 if(u!=v){ 44 p[u]=v; 45 ans+=d; 46 used.push_back(e[i]); 47 if(--cnt==1) break; 48 } 49 } 50 return ans; 51 } 52 53 int main(){ 54 // freopen("in.txt","r",stdin); 55 // freopen("outttttttt.txt","w",stdout); 56 int T,q; 57 scanf("%d",&T); 58 while(T--){ 59 scanf("%d%d",&n,&q); 60 for(int i=0;i<q;i++){ 61 int cnt; 62 scanf("%d %d",&cnt,&cost[i]); 63 subn[i].clear(); 64 while(cnt--){ 65 int u; 66 scanf("%d",&u); 67 subn[i].push_back(u-1); 68 } 69 } 70 71 for(int i=0;i<n;i++) scanf("%d %d",&x[i],&y[i]); 72 73 vector<edge> e,need; 74 75 for(int i=0;i<n;i++) 76 for(int j=i+1;j<n;j++){ 77 int c=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); 78 e.push_back(edge(i,j,c)); 79 } 80 81 for(int i=0;i<n;i++) p[i]=i; 82 sort(e.begin(),e.end()); 83 84 int ans=mst(n,e,need); 85 86 for(int mask=0;mask<(1<<q);mask++){ 87 88 for(int i=0;i<n;i++) p[i]=i; 89 int cnt=n,c=0; 90 91 for(int i=0;i<q;i++) if(mask & (1<<i)){ 92 c+=cost[i]; 93 for(int j=1;j<subn[i].size();j++){ 94 int u=find(subn[i][j]),v=find(subn[i][0]); 95 if(u!=v){p[u]=v;cnt--;} 96 } 97 } 98 vector<edge> dummy; 99 ans=min(ans,c+mst(cnt,need,dummy)); 100 } 101 printf("%d\n",ans); 102 if(T) printf("\n"); 103 } 104 return 0; 105 }
时间: 2024-10-14 07:10:23