zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    敲七
    二维指针数组**p
    食物链(待解决)
    蛇行矩阵
    快速排序 QuickSort
    堆排序
    猪的安家
    百度语言翻译机
    HTML <base> 标签
    免费网络管理流量监控软件大比拼
  • 原文地址:https://www.cnblogs.com/lokiii/p/8931461.html
Copyright © 2011-2022 走看看