zoukankan      html  css  js  c++  java
  • 【洛谷6898】[ICPC2014 WF] Metal Processing Plant(二分图染色+2-SAT)

    点此看题面

    • 给定(n)个点,每两个点之间有一个矛盾值。
    • 要求将这些点划分成两个点集,使得两个点集的最大矛盾值之和最小。
    • (nle200)

    二分图染色

    考虑我们从大到小枚举较大的那个矛盾值(x),显然矛盾值大于(x)的一对点无法放在同一个集合中,我们可以在它们之间连一条边。

    这样一来,发现必须要满足当前是一张二分图,而对于图中每一个连通块,它的两部分必须分别放在两个点集中。

    由于每次我们只会加入一条边,先判断是否形成了奇环(在同一连通块中且颜色相同),否则如果它们不连通就合并两个连通块(不用显式建图(dfs),可以直接暴枚一遍所有点更新所在连通块)。

    (2-SAT)

    我们二分另一个最大矛盾值。

    对于矛盾值大于二分值的一对点,它们不能同时被选在这个点集中,也就是它们对应连通块的对应部分不能同时被选在这个点集中。

    每个连通块必须要在两种决策中选择一种,又有着这些条件表达式,发现就是一个经典的(2-SAT)问题。

    注意,我们只需在二分图连通块情况改变时做一遍二分答案+(2-SAT),因此只会做(O(n))次。

    代码:(O(n^3logn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200
    using namespace std;
    int n,c[N+5],p[N+5],a[N+5][N+5];
    struct Data {int x,y,v;I bool operator < (Con Data& o) Con {return v>o.v;}}s[N*N+5];
    namespace TwoSAT//2-SAT
    {
    	#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    	int ee,lnk[2*N+5];struct edge {int to,nxt;}e[N*N+5];
    	int d,dfn[2*N+5],low[2*N+5],T,S[2*N+5],IS[2*N+5],ct,bl[2*N+5];
    	I void Tarjan(CI x)
    	{
    		dfn[x]=low[x]=++d,IS[S[++T]=x]=1;for(RI i=lnk[x];i;i=e[i].nxt)
    			low[x]=min(low[x],dfn[e[i].to]?(IS[e[i].to]?dfn[e[i].to]:n<<1):(Tarjan(e[i].to),low[e[i].to]));
    		if(dfn[x]==low[x]) {++ct;W(bl[S[T]]=ct,IS[S[T]]=0,S[T--]^x);}
    	}
    	I bool Check(CI x)//检验答案
    	{
    		RI i,j;for(ee=d=ct=0,i=1;i<=2*n;++i) lnk[i]=dfn[i]=0;//情况
    		for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) a[i][j]>x&&//矛盾值大于x不能同时选择
    			(add(p[i]+c[i]*n,p[j]+(c[j]^1)*n),add(p[j]+c[j]*n,p[i]+(c[i]^1)*n));//把条件式表示成图中边
    		for(i=1;i<=n;++i) i==p[i]&&(!dfn[i]&&(Tarjan(i),0),!dfn[i+n]&&(Tarjan(i+n),0));//Tarjan
    		for(i=1;i<=n;++i) if(i==p[i]&&bl[i]==bl[i+n]) return 0;return 1;//两种选择在同一强连通分量中说明无解
    	}
    }
    int res;I void Calc() {RI l=0,r=1e9,mid;W(l^r) TwoSAT::Check(mid=l+r-1>>1)?r=mid:l=mid+1;res=r;}//二分答案
    I bool Link(CI x,CI y)//二分图连边
    {
    	if(p[x]==p[y]) return c[x]^c[y];RI f=p[y],w=c[x]^c[y]^1;
    	for(RI i=1;i<=n;++i) p[i]==f&&(p[i]=p[x],c[i]^=w);return Calc(),true;//暴枚所有点,若与y同连通块就更新
    }
    int main()
    {
    	RI i,j,t=0;if(scanf("%d",&n),n==1) return puts("0"),0;
    	for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) scanf("%d",&a[i][j]),s[++t]=(Data){i,j,a[i][j]};
    	RI ans=2e9;for(sort(s+1,s+t+1),i=1;i<=n;++i) p[i]=i;Calc();
    	for(i=1;i<=t;++i) if(ans=min(ans,s[i].v+res),!Link(s[i].x,s[i].y)) break;//从大到小枚举边权
    	return i>t&&(ans=min(ans,res)),printf("%d
    ",ans),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Account group in ERP and its mapping relationship with CRM partner group
    错误消息Number not in interval XXX when downloading
    错误消息Form of address 0001 not designated for organization
    Algorithm类介绍(core)
    梯度下降与随机梯度下降
    反思
    绘图: matplotlib核心剖析
    ORB
    SIFT
    Harris角点
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6898.html
Copyright © 2011-2022 走看看