紫书P358
收获:
1:用vector建立需要的边,和原本就有的边
2:这里的subn用vector其实是很正常的,但是我可能原本想不出要用这个
3:掩码mask在这里的表示要更加熟练
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<stack>
#include<cmath>
#include<map>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
#define INF 1000000000
#define bug1 cout<<"bug1"<<endl;
#define bug2 cout<<"bug2"<<endl;
#define bug3 cout<<"bug3"<<endl;
using namespace std;
const int maxn=1005;
const int maxq=10;
int cost[10];
int fa[maxn];
int n;
vector<int>subn[maxq];
int x[maxn],y[maxn];
struct Edge{
int u,v,d;
Edge(int u,int v,int d):u(u),v(v),d(d){}
bool friend operator<(Edge a,Edge b){
return a.d<b.d;
}
};
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int MST(int cnt, const vector<Edge>&e, vector<Edge>&used) {
if(cnt == 1) return 0;
int m = e.size();
int ans = 0;
used.clear();
for(int i = 0; i < m; i++) {
int u = find(e[i].u),v= find(e[i].v);
int d = e[i].d;
if(u != v) {
fa[u] = v;
ans += d;
used.push_back(e[i]);
if(--cnt == 1) break;
}
}
return ans;
}
vector<Edge>e,need;
void init(){
for(int i=0;i<n;++i)fa[i]=i;
memset(x,0,sizeof(x));
memset(y,0,sizeof(y));
memset(cost,0,sizeof(cost));
e.clear();need.clear();
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int q;
scanf("%d%d",&n,&q);
init();//天哪,又忘了这个地方中的init应该放在输入n的后面
for(int i=0;i<q;++i){
int cnt;
scanf("%d%d",&cnt,&cost[i]);
subn[i].clear();
for(int j=1;j<=cnt;++j){
int tmp;scanf("%d",&tmp);
subn[i].push_back(tmp-1);//庲自己错误的地方在这,依然还是和0有关
}
}
for(int i = 0; i < n; i++) scanf("%d%d", &x[i], &y[i]);
for(int i=0;i<n;++i){
for(int j=i+1;j<n;++j){
int c= (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]);//因为这道题要求的不是最小生成树的距离大小,而且为了防止精度误差,
e.push_back(Edge(i,j,c));//所以就直接不开根号了
}
}
for(int i=0;i<n;++i)fa[i]=i;
sort(e.begin(),e.end());
int ans=MST(n,e,need);
for(int mask=0;mask<(1<<q);++mask){
for(int i=0;i<n;++i)fa[i]=i;
int cnt=n,c=0;
for(int i=0;i<q;++i)if(mask&(1<<i)){
c+=cost[i];
for(int j=1;j<subn[i].size();++j){
int u=find(subn[i][j]),v=find(subn[i][0]);
if(v!=u){
fa[v]=u;
cnt--;
}
}
}
vector<Edge>tmp;
ans=min(ans,c+MST(cnt,need,tmp));
}
printf("%d\n",ans);
if(t)printf("\n");
}
}
本文详细介绍了使用最小生成树算法解决特定问题的过程,包括如何利用vector存储边信息、子节点集合以及掩码(mask)的使用技巧。通过实例展示了算法的具体实现步骤,并提供了完整的C++代码实现。
329

被折叠的 条评论
为什么被折叠?



