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*/