问题转化就是给定
n
n
个二元组,每组中选出一个使得其互不相同,最大化另一个的和。
那么对于每个二元组我们对这两个值连一条无向边,现在的问题就是对每一条边定向使得每个点出度,并最大化每个点乘上其入度的和。
那么有解一定是若干个树和环套树,对于环套树的情况定向方式是唯一的,这样每个点贡献
degi−1
d
e
g
i
−
1
次,
degi
d
e
g
i
表示其度数;对于树的情况根节点可以多贡献一次,我们选出其中最大的贡献
degi
d
e
g
i
次,其它的贡献
degi−1
d
e
g
i
−
1
次即可。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 250010
#define ll long long
using namespace std;
int m,n,tote,a[N],b[N],con[N<<1],nxt[N<<2],to[N<<2],mx,z[N<<1],deg[N<<1];
ll ans;
bool vis[N<<1],flag;
void ins(int x,int y)
{
to[++tote]=y;
nxt[tote]=con[x];
con[x]=tote;
}
void dfs(int v,int q)
{
mx=max(mx,z[v]);vis[v]=1;
for(int p=con[v];p;p=nxt[p])
if((p^q)!=1)
if(vis[to[p]]) flag=1;
else dfs(to[p],p);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
z[2*i-1]=a[i];z[2*i]=b[i];
}
sort(z+1,z+2*n+1);
m=unique(z+1,z+2*n+1)-z-1;
tote=1;
for(int i=1;i<=n;i++)
{
int x=lower_bound(z+1,z+m+1,a[i])-z,y=lower_bound(z+1,z+m+1,b[i])-z;
ins(x,y);ins(y,x);
deg[x]++;deg[y]++;
}
for(int i=1;i<=m;i++)
if(!vis[i])
{
flag=0;mx=0;
dfs(i,0);
if(!flag) ans+=mx;
}
for(int i=1;i<=m;i++)
ans+=(ll)z[i]*(deg[i]-1);
printf("%lld",ans);
return 0;
}