https://www.jisuanke.com/contest/7196/466924
题意:
给出一个n个点带权无向完全图,对于一个环(只考虑边可以有重点),其权值为任意两条相邻边的权值max的和。
现在将图分成多个环(无边交集,并集为完全图),图的值为每个环的权值之和,求其最小值。
解析:
思路:每条边,如果其权值大,那么尽可能接连权值较大的边。
将边按照权值排序,从大的开始取。
对于当前边的左右顶点,分别去判断是否可以连到之前的大权值边上,可以就连上去(link[i][0]表示第条边的左顶点连接的边)
由于每个点只会有一条空出来边(没连上的大权值边),所以用一个数组来记录没有匹配的大权边。
代码:
/*
* Author : Jk_Chen
* Date : 2020-04-12-12.11.44
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e6+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n;
struct node{
int x,y,w;
bool operator<(const node &A)const{return w<A.w;}
}e[maxn];
int link[maxn][2];
int nowedge[1009];
LL ans;
bool vis[maxn];
void dfs(int ed,int preed){
if(preed!=-1)
vis[ed]=1,ans+=max(e[preed].w,e[ed].w);
int p=0;
if(e[ed].x==e[preed].x||e[ed].x==e[preed].y)p=1;
int nexed=link[ed][p];
if(vis[nexed])return;
dfs(nexed,ed);
}
int main(){
n=rd;
int m=n*(n-1)/2;
rep(i,1,m){
e[i].x=rd;
e[i].y=rd;
e[i].w=rd;
}
sort(e+1,e+1+m);
per(i,m,1){
int x=e[i].x,y=e[i].y,w=e[i].w;
int ed=nowedge[x];
if(ed){
int p=(e[ed].x==x?0:1);
link[ed][p]=i;
link[i][0]=ed;
nowedge[x]=0;
}
else{
nowedge[x]=i;
}
ed=nowedge[y];
if(ed){
int p=(e[ed].x==y?0:1);
link[ed][p]=i;
link[i][1]=ed;
nowedge[y]=0;
}
else{
nowedge[y]=i;
}
}
rep(i,1,m){
if(!vis[i])dfs(i,-1);
}
printf("%lld\n",ans);
return 0;
}
/*_________________________________________________________end*/