题面甚至没给范围,由数据可得n<=200。容易想到二分答案,暴力枚举某集合的价值,2-SATcheck一下即可。这样是O(n4logn)的。
2-SAT复杂度已经是下界,考虑如何优化枚举。稍微改一下,不妨从大到小枚举较大的集合价值(即枚举边),另一个集合二分答案,同样O(n4logn)。
看起来没什么卵用。但注意到较大集合所不能包含的边不可以成奇环,否则肯定有一条环上边被选中。那么考虑当前边,如果形成奇环,最大值不可能比它更小了,做完这个就可以退出;如果加上这条边后形成偶环,可以直接跳过,因为如果要让其被选中,相当于将偶环缩成了奇环,剩余边肯定有一条被选中而又比它大。不形成环时则直接做。由于树边数量O(n),复杂度O(n3logn)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define ll long long #define N 210 #define inf 1000000010 int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N][N],b[N*N],dfn[N<<1],low[N<<1],stk[N<<1],belong[N<<1],p[N<<1],fa[N<<1],deep[N<<1],size[N<<1],len[N<<1],t,top,tot,cnt,ans=inf,m; bool flag[N<<1]; struct data{int to,nxt; }edge[N*N<<3]; struct data2 { int x,y,z; bool operator <(const data2&a) const { return z<a.z; } }e[N*N]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void tarjan(int k) { dfn[k]=low[k]=++cnt; stk[++top]=k;flag[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (!dfn[edge[i].to]) tarjan(edge[i].to),low[k]=min(low[k],low[edge[i].to]); else if (flag[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]); if (dfn[k]==low[k]) { tot++; while (stk[top]!=k) { flag[stk[top]]=0; belong[stk[top]]=tot; top--; } flag[k]=0,belong[k]=tot,top--; } } bool check(int x,int y) { memset(dfn,0,sizeof(dfn)); memset(p,0,sizeof(p));t=tot=cnt=0; for (int i=1;i<n;i++) for (int j=i+1;j<=n;j++) { if (a[i][j]>x) addedge(i*2-1,j*2),addedge(j*2-1,i*2); if (a[i][j]>y) addedge(i*2,j*2-1),addedge(j*2,i*2-1); } for (int i=1;i<=n*2;i++) if (!dfn[i]) tarjan(i); for (int i=1;i<=n;i++) if (belong[i*2-1]==belong[i*2]) return 0; return 1; } int find(int x) { if (fa[x]==x) return x; int f=find(fa[x]); deep[x]=deep[fa[x]]^len[x]; return f; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4078.in","r",stdin); freopen("bzoj4078.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); for (int i=1;i<n;i++) for (int j=i+1;j<=n;j++) { a[i][j]=a[j][i]=read(); m++;e[m].z=a[i][j],e[m].x=i,e[m].y=j; } sort(e+1,e+m+1); for (int i=1;i<=n*2;i++) fa[i]=i,size[i]=1; for (int i=m;i>=1;i--) { int p=find(e[i].x),q=find(e[i].y); if (size[p]<size[q]) swap(p,q); if (p!=q||(deep[e[i].x]^deep[e[i].y]^1)) { if (p!=q) fa[q]=p,size[p]+=size[q],len[q]=deep[e[i].x]^deep[e[i].y]^1; int l=0,r=i,u=inf; while (l<=r) { int mid=l+r>>1; if (check(e[i].z,e[mid].z)) u=e[mid].z,r=mid-1; else l=mid+1; } ans=min(ans,e[i].z+u); } if (p==q&&(deep[e[i].x]^deep[e[i].y]^1)) break; } if (ans==inf) ans=0;cout<<ans; return 0; }