//链式前向星存图 structEdge { int to, w, next; }edge[N]; int head[N], cnt; int n, m, ans; //Prim算法需要的两个数组 int dis[N]; bool vis[N]; //加边 voidadd_edge(int u, int v, int w){ edge[++cnt].next = head[u]; edge[cnt].to = v; edge[cnt].w = w; head[u] = cnt; } voidPrim(){ //默认从1开始,则从2起,我们需要把dis设置为极大值 for (int i=2;i<=n;i++){ dis[i]=INF; } //首先从1开始,设置与1相连的所有边的权值 for (int i=head[1];i;i=edge[i].next){ int v=edge[i].to; dis[v]=min(dis[v],edge[i].w);//可能存在重边 } int now=1;//当前点为1 //注意:i少遍历一次,因为1省略了 for (int i=1;i<n;i++){ vis[now]=true; int minF=INF; //遍历所有的点,找到未遍历过的,并且边权值最小的那一条边 for (int j=1;j<=n;j++){ if (!vis[j] && dis[j]<minF){ minF=dis[j]; //这一条边的权值 now=j; //当前这条边的一个顶点 } } ans+=minF; //边权相加 //遍历所有与now相连的边 for (int j=head[now];j;j=edge[j].next){ int v=edge[j].to; //边的另一个顶点 if (!vis[v] && dis[v]>edge[j].w){ //更新dis数组中这边 dis[v]=edge[j].w; } } } for (int i=1;i<=n;i++){ if (dis[i]==INF){ cout<<"improssible\n"; return; } } cout<<ans; }
#include<iostream> #include<cstring> #include<algorithm> #include<vector> usingnamespace std; #define int long long typedef pair<int, int> PII; constint N = 2e3+10,M=3e6+10,INF=9999999999; //建边 structEdge{ int to,next; int w; }edge[M<<1];//边集合 int head[N],cnt; //main int n; PII pos[N]; int c[N],k[N]; vector<int> vec1; vector<PII> vec2; //Prim算法 bool vis[N]; int fa[N],dis[N]; //--------------------------------------- voidadd_edge(int u,int v,int w){ edge[++cnt].next=head[u]; edge[cnt].to=v; edge[cnt].w=w; head[u]=cnt; } intget_dis(int x,int y){ int dx=abs(pos[x].first-pos[y].first); int dy=abs(pos[x].second-pos[y].second); return (int)(dx+dy)*(k[x]+k[y]); } intPrim(){ for (int i=0;i<=n;i++){ dis[i]=INF; } //建立超级源点:0连接到每一个点 for (int i = 1; i <= n; i ++ ){ add_edge(i,0,c[i]); add_edge(0,i,c[i]); } //设置初始边权值:遍历与超级源点相连的每一个边,计算出初始边权值 for (int i = head[0]; i ; i = edge[i].next ){ int v=edge[i].to; dis[v]=min(dis[v],edge[i].w); } int now=0;//当前处理的点 int ans=0;//答案 //遍历到n-1 for (int i=0;i<n;i++){ vis[now]=true; int minF=INF; //遍历所有的没有被访问过的点,找出最小权值的边 for (int j = 1; j <= n; j ++ ){ if (!vis[j] && dis[j]<minF){ minF=dis[j]; now=j; } } ans+=minF; if (!fa[now]){ //如果fa[now]==0,则意味着这个点的父节点是超级源点,则在图中就表示为他与超级源点相连,只能建电站 vec1.push_back(now); } else{ //如果不为0,则意味着这个点与原图中的某个点相连,则它与这个点之间建电线 vec2.push_back({now,fa[now]}); } //更新dis数组,遍历所有的now的相连的边 for (int j=head[now];j;j=edge[j].next){ int v=edge[j].to; if (!vis[v] && dis[v] > edge[j].w){ dis[v] = edge[j].w; fa[v]=now; } } } return ans; } signedmain(){ cin>>n; for (int i = 1; i <= n; i ++ ){ cin>>pos[i].first>>pos[i].second; } for (int i = 1; i <= n; i ++ ){ cin>>c[i]; } for (int i = 1; i <= n; i ++ ){ cin>>k[i]; } for (int i=1;i<=n;i++){ for (int j=1;j<i;j++){ int w=get_dis(i,j); add_edge(i,j,w); add_edge(j,i,w); } } cout<<Prim()<<endl; cout<<vec1.size()<<endl; for (auto &x:vec1) cout<<x<<' '; cout<<endl<<vec2.size()<<endl; for (auto &x:vec2) cout<<x.first<<' '<<x.second<<endl; return0; }
#include<iostream> #include<cstring> #include<algorithm> usingnamespace std; #define int long long constint N = 2e3+10; structEdge{ int a,b,c; booloperator<(const Edge& p){ return c<p.c; } }edge[N*N]; int n,m; typedef pair<int, int> PII; PII pos[N]; int c[N],k[N]; int e;//总边数 int parent[N]; bool vis[N*N]; intget_dis(int p1,int p2){ int dx=abs(pos[p1].first-pos[p2].first); int dy=abs(pos[p1].second-pos[p2].second); return (int)(dx+dy)*(k[p1]+k[p2]); } intfind(int x)// 并查集 { if (parent[x] != x) parent[x] = find(parent[x]); return parent[x]; }
intkruskal(){ //超级源点连边 for (int i = 1; i <= n; i ++ ){ edge[++e]={i,0,c[i]}; } //初始化并查集 for (int i=1;i<=n;i++){ parent[i]=i; } //排序边集合 sort(edge+1,edge+1+e); vis[0]=true; int ans=0; for (int i=1;i<=e;i++){ int a=edge[i].a,b=edge[i].b,c=edge[i].c; int pa=find(a),pb=find(b); if (pa!=pb){ parent[pa]=pb; ans+=c; vis[i]=true; } } return ans; } signedmain() { cin>>n; for (int i = 1; i <= n; i ++ ){ cin>>pos[i].first>>pos[i].second; } for (int i = 1; i <= n; i ++ ){ //建电站 cin>>c[i]; } for (int i = 1; i <= n; i ++ ){ //建电线 cin>>k[i]; } for (int i = 1; i <= n; i ++ ){ for (int j = 1; j < i; j ++ ){ int w=get_dis(i,j); edge[++e]={i,j,w}; } } vector<int> vec1; vector<PII> vec2; cout<<kruskal()<<endl; for (int i=1;i<=e;i++){ if (vis[i]){ if (edge[i].b==0){ vec1.push_back(edge[i].a); } else{ vec2.push_back({edge[i].a,edge[i].b}); } } } cout<<vec1.size()<<endl; for (auto& x:vec1) cout<<x<<' '; cout<<endl<<vec2.size()<<endl; for (auto& x:vec2) cout<<x.first<<" "<<x.second<<'\n'; return0; }