BZOJ4078 WF2014Metal Processing Plant(二分答案+2-SAT)

  题面甚至没给范围,由数据可得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\n";
#else
    const char LL[]="%lld\n";
#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;
}
 

 

posted @ 2019-01-02 00:32  Gloid  阅读(247)  评论(0编辑  收藏  举报