bzoj 4078: [Wf2014]Metal Processing Plant【二分+2-SAT+枚举+并查集】

枚举从大到小s1,二分s2(越大越有可能符合),2-SAT判断,ans取min
思路倒是挺简单的,就是二分的时候出了比较诡异的问题,只能二分s2的值,不能在数组上二分...
有个优化,就是当不是二分图的时候退出枚举,这个用并查集染色维护

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=405;
int n,a[N][N],tot,has,h[N],cnt,ans=2e9,f[N],d[N],dfn[N],low[N],s[N],top,bl[N],dft,col;
bool v[N];
struct qwe
{
    int ne,to,va;
}e[N*N];
struct bian
{
    int u,v,w;
}b[N*N];
bool cmp(const bian &a,const bian &b)
{
    return a.w>b.w||(a.w==b.w&&a.u>b.u)||(a.w==b.w&&a.u==b.u&&a.v>b.v);
}
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
inline int zhao(int x)
{
    if(f[x]==x) 
        return x;  
    int res=zhao(f[x]);  
    d[x]^=d[f[x]];  
    return f[x]=res;  
}   
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
void tarjan(int u)
{
    low[u]=dfn[u]=++dft;
    v[s[++top]=u]=1;
    for(int i=h[u];i;i=e[i].ne)
    {
        if(!dfn[e[i].to])
        {
            tarjan(e[i].to);
            low[u]=min(low[u],low[e[i].to]);
        }
        else if(v[e[i].to])
            low[u]=min(low[u],dfn[e[i].to]);
    }
    if(dfn[u]==low[u])
    {
        col++;
        while(s[top]!=u)
        {
            bl[s[top]]=col;
            v[s[top--]]=0;
        }
        bl[s[top]]=col;
        v[s[top--]]=0;
    }
}
bool ok(int s1,int s2)
{
    memset(h,0,sizeof(h));
    memset(dfn,0,sizeof(dfn));
    cnt=0;dft=0;col=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(a[i][j]>s1)
                add(i+n,j),add(j+n,i);
            if(a[i][j]>s2)
                add(i,j+n),add(j,i+n);
        }
    for(int i=1;i<=n+n;i++)
        if(!dfn[i])
            tarjan(i);
    for(int i=1;i<=n;i++)
        if(bl[i]==bl[i+n])
            return 0;
    return 1;
}
void wk(int c)
{
    // int l=c,r=tot,an=0;
    // while(l<=r)
    // {
        // int mid=(l+r)>>1;
        // if(ok(b[c].w,b[mid].w))
            // l=mid+1,an=mid;
        // else
            // r=mid-1;
    // }
    // if(an)
        // ans=min(ans,b[c].w+b[an].w);
    int l=0,r=b[c].w;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(ok(b[c].w,mid))
            r=mid-1;
        else
            l=mid+1;
    }
    ans=min(ans,b[c].w+l);
}
int main()
{
    n=read();
    if(n<=2)
    {
        puts("0");
        return 0;
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        {
            a[i][j]=a[j][i]=read();
            b[++tot]=(bian){i,j,a[i][j]};
        }
    sort(b+1,b+1+tot,cmp);
    for(int i=1;i<=n;i++)
        f[i]=i;
    for(int i=1;i<=tot;i++)
    {
        int fu=zhao(b[i].u),fv=zhao(b[i].v);
        if(fu!=fv)
        {
            wk(i);
            d[fu]=d[b[i].u]^d[b[i].v]^1;
            f[fu]=fv;
        }
        else if(d[b[i].u]==d[b[i].v])
        {
            wk(i);
            break;
        }
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2018-04-24 16:27  lokiii  阅读(315)  评论(0编辑  收藏  举报