• 【刷题】BZOJ 4078 [Wf2014]Metal Processing Plant


    Description

    定义集合S的价值D(S)为:

    现在给你n个元素,并给出其中任意两个元素之间的d(i,j)值

    要你将这些元素划分成两个集合A、B。

    求min{D(A)+D(B)}。

    注:d(i,j)=d(j,i)。

    Input

    输入数据的第一行是一个整数n,代表元素个数。

    之后n-1行描述的是d(i,j),第i行包含n-i个整数,第i行第j列的整数代表的是d(i,i+j)。

    0<=wi<=10^9

    Output

    输出只有一行,一个整数,代表min{D(A)+D(B)}。

    Sample Input

    5

    4 5 0 2

    1 3 7

    2 0

    4

    Sample Output

    4

    Solution

    最开始考虑枚举两个集合的上限,于是就会出现“某个点在A集合,另一个点就不能在A集合”的限制,这就是个2-SAT

    所以朴素算法就是枚举两个集合的上限,然后建边跑2-SAT判可行性,最后将两个集合的上限的和对答案chkmin

    考虑优化

    可以发现在最优解的状态下,随着A集合上限的增大,B集合的上限是减小的,于是就可以用两个指针从两端往中间枚举,但这样还是有点慢

    再考虑优化

    发现A集合上限的变大对图的影响仅仅只是需要删掉一些边,而B集合上限的减小对图的影响仅仅只是需要加一些边

    所以在枚举上限之后可以不重新建图,而是加入和删除一些边

    这样就可以跑过了

    然而还有一些奇环偶环之类的优化,可惜不会,就没写了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const int MAXN=400+10,MAXM=MAXN*MAXN+10;
    int n,d[MAXN][MAXN],ans,mxval,beg[MAXN],e,nex[MAXM<<2],to[MAXM<<2],DFN[MAXN],LOW[MAXN],Visit_Num,Stack[MAXN],In_Stack[MAXN],Stack_Num,Be[MAXN],cnt,vt,V[MAXM],Lt,Rt;
    struct node{
    	int u,v,w;
    	inline bool operator < (const node &A) const {
    		return w<A.w;
    	};
    };
    node L[MAXM],R[MAXM];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void insert(int x,int y)
    {
    	to[++e]=y;
    	nex[e]=beg[x];
    	beg[x]=e;
    }
    inline void Tarjan(int x)
    {
    	DFN[x]=LOW[x]=++Visit_Num;
    	In_Stack[x]=1;
    	Stack[++Stack_Num]=x;
    	for(register int i=beg[x];i;i=nex[i])
    		if(!DFN[to[i]])Tarjan(to[i]),chkmin(LOW[x],LOW[to[i]]);
    		else if(In_Stack[to[i]]&&DFN[to[i]]<LOW[x])LOW[x]=DFN[to[i]];
    	if(DFN[x]==LOW[x])
    	{
    		int temp;++cnt;
    		do{
    			temp=Stack[Stack_Num--];
    			In_Stack[temp]=0;
    			Be[temp]=cnt;
    		}while(temp!=x);
    	}
    }
    inline bool check()
    {
    	for(register int i=2;i<=(n<<1|1);++i)DFN[i]=LOW[i]=0;
    	for(register int i=2;i<=(n<<1|1);++i)
    		if(!DFN[i])Tarjan(i);
    	for(register int i=2;i<=(n<<1|1);i+=2)
    		if(Be[i]==Be[i^1])return false;
    	return true;
    }
    inline void init()
    {
    	for(register int i=1;i<=n;++i)
    		for(register int j=1;j<=n;++j)
    			if(i!=j)
    			{
    				insert(i<<1,j<<1|1),L[++Lt]=(node){i<<1,j<<1|1,d[i][j]};
    				R[++Rt]=(node){i<<1|1,j<<1,d[i][j]};
    			}
    }
    inline void add(int id)
    {
    	insert(R[id].u,R[id].v);
    }
    inline void del(int id)
    {
    	int u=L[id].u,v=L[id].v,i,las=0;
    	for(i=beg[u];i&&to[i]!=v;i=nex[las=i]);
    	if(las)nex[las]=nex[i];
    	else beg[u]=nex[i];
    }
    int main()
    {
    	read(n);
    	for(register int i=1;i<n;++i)
    		for(register int j=1;j<=n-i;++j)read(d[i][i+j]),V[++vt]=d[i][i+j];
    	for(register int i=1;i<=n;++i)
    		for(register int j=i+1;j<=n;++j)d[j][i]=d[i][j],chkmax(mxval,d[i][j]);
    	init();
    	V[++vt]=0;ans=mxval;
    	std::sort(V+1,V+vt+1);
    	std::sort(L+1,L+Lt+1);
    	std::sort(R+1,R+Rt+1);
    	vt=std::unique(V+1,V+vt+1)-V-1;
    	for(register int i=1,j=vt,lp=1,rp=Rt;i<=vt&&i<=j;++i)
    	{
    		while(lp<=Lt&&L[lp].w<=V[i])del(lp),lp++;
    		while(j>=i&&check())
    		{
    			--j;
    			while(rp>=1&&R[rp].w>V[j])add(rp),rp--;
    		}
    		chkmin(ans,V[i]+V[j+1]);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    PHP识别验证码-image-ocr
    Session的一些小疑问
    PHP-webdriver自动化测试完成登录
    大文件日志快速解析入库
    Linux权限说明
    使用python的selenium自动化登录获取cookie
    PHP编码的注释规范
    MySQL主主架构、读写分离搭建学习
    用docker尝试nginx的负载均衡
    lua require
  • 原文地址:https://www.cnblogs.com/hongyj/p/9544256.html
Copyright © 2020-2023  润新知