不妨设 D(S)<=D(T) D ( S ) <= D ( T ) ,我们可以从大到小去枚举是哪条边贡献到 D(T) D ( T ) ,对于 D(S) D ( S ) 显然满足二分性,我们可以二分他,然后对于边权 >D(T) > D ( T ) 的边,他的两端点不能在同一个集合里,对于边权在 (D(S),D(T)] ( D ( S ) , D ( T ) ] 内的边,他的两端点不能都在A里,我们可以建出一个图跑 2−SAT 2 − S A T ,那么当前的复杂度是 O(n4logn2) O ( n 4 l o g n 2 ) 的
这个复杂度太大,我们尝试去优化
D(T)
D
(
T
)
的枚举,每次我们计算完
D(T)
D
(
T
)
的贡献后,将这条边建进图中,那么当图中存在奇环时就不需要再枚举了,因为这些边权
>D(T)
>
D
(
T
)
,两端点不能在同一个集合里,奇环说明这个图不是二分图,就不能做到任意一条边的两端都不在一个集合里
此外还有一个性质,就是这个图中任意一个偶环的最小边一定不会成为
D(T)
D
(
T
)
,因为如果他对
D(T)
D
(
T
)
产生贡献,说明他的两端点在同一集合里,因为他是个偶环,所以一定还存在另外一条边,满足两端点在同一集合里且权值>当前枚举的D(T)
所以我们枚举边时,将他加入图中,若他在一个偶环上,则不需要处理这条边,若他在一个奇环上,计算完这条边的贡献后就可以退出,那么我们实际上只需要对 O(n) O ( n ) 条边去二分统计贡献,复杂度就降到了 O(n3logn2) O ( n 3 l o g n 2 )
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(int &x)
{
char c;while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
inline void down(int &a,const int &b){if(a>b)a=b;}
const int maxn = 505;
int n;
int mp[maxn][maxn];
struct edge{int y,nex;}a[maxn*maxn*2]; int len,fir[maxn];
inline void ins(const int x,const int y){a[++len]=(edge){y,fir[x]};fir[x]=len;}
int dfn[maxn],low[maxn],id;
int t[maxn],tp; bool insta[maxn];
int bel[maxn],cnt;
void tarjan(const int x)
{
dfn[x]=low[x]=++id;
insta[t[++tp]=x]=true;
for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y)
{
if(!dfn[y]) tarjan(y),down(low[x],low[y]);
else if(insta[y]) down(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
++cnt; int la=0;
while(la!=x)
{
insta[la=t[tp--]]=false;
bel[la]=cnt;
}
}
}
int fa[maxn],fas[maxn];
int findfa(const int x)
{
if(fa[x]==x) return x;
int k=findfa(fa[x]);
fas[x]=fas[x]^fas[fa[x]];
return fa[x]=k;
}
struct ei
{
int i,j,w;
friend inline bool operator <(const ei x,const ei y){return x.w<y.w;}
}e[maxn*maxn]; int en;
bool judge(int x,int y)
{
len=id=cnt=0;
memset(fir,0,sizeof fir);
memset(dfn,0,sizeof dfn);
for(int k=x+1;k<=en;k++)
{
int i=e[k].i,j=e[k].j;
if(e[k].w>e[x].w) ins(i,j+n),ins(j,i+n);
if(e[k].w>e[y].w) ins(i+n,j),ins(j+n,i);
}
for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++) if(bel[i]==bel[i+n]) return false;
return true;
}
int ans;
void solve()
{
for(int i=1;i<=n;i++) fa[i]=i,fas[i]=0;
sort(e+1,e+en+1); e[en+1].w=e[en].w+1;
for(int R=en;R>=1;R--)
{
int x=e[R].i,y=e[R].j;
int f1=findfa(x),f2=findfa(y);
if(f1==f2&&fas[x]!=fas[y]) continue;
//search
int l=0,r=R-1;
while(l<=r)
{
int mid=l+r>>1;
if(judge(mid,R)) r=mid-1;
else l=mid+1;
}
down(ans,e[R].w+e[++r].w);
//merge
if(f1!=f2) fa[f1]=y,fas[f1]=!fas[x];
else return;
}
}
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
while(scanf("%d",&n)!=EOF)
{
en=0;
for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++)
{
read(mp[i][j]);
mp[j][i]=mp[i][j];
e[++en]=(ei){i,j,mp[i][j]};
}
if(n<=2) { puts("0");continue; }
ans=INT_MAX; solve();
printf("%d\n",ans);
}
return 0;
}