• 【洛谷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;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Notepad++ 文件丢失了,找回历史文件方法
    oracle数据库连接问题org.springframework.jdbc.support.MetaDataAccessException: JDBC DatabaseMetaData method not implemented by JDBC driver
    Windows下安装Oracle 11g 2版 64位,从下载,安装,测试连接成功~!
    Windows设置 .exe 开机自启动
    设置VMware 以及指定 虚拟机 ,开机自启动
    实体类与数据库字段不匹配问题,java.sql.SQLSyntaxErrorException: Unknown column 'xxx' in 'field list'
    springboot访问出错,mapperScan导包错误java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseSelectProvider.<init>() at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_172] at java.
    Google浏览器显示URL的 http https ....
    跑满带宽的一款百度网盘下载工具 : PanDownload
    免费使用Google
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6898.html
Copyright © 2020-2023  润新知