• 拟阵交 学习笔记


    总觉得在大考前学习新知识点不太好。
    模拟赛考了一道拟阵交。。。。。
    拟阵是一个集合的集合(二元组((S,U))其中(S)是集合内集合元素的取值,(U)是集合内的集合),满足2条公理:
    遗传性:若拟阵中有一集合(S),则(S-{x})依然在拟阵中
    交换性:若有二集合(S1,S2)(card(S1)<card(S2))
    则存在一元素(x)(S2-S1)中且(S1+x)仍然属于拟阵。
    定义基:拟阵中加入任何元素都不在拟阵的集合
    定义环:不在拟阵中,且任意删除一个元素后在拟阵中的集合。
    引理1:所有基的大小相同
    引理2:如果存在两个不同的基(A,B),令(x)(A-B)的任意元素,(y)(B-A)的任意元素
    (A-{x}+{y})在拟阵中。
    引理3:如果存在2个环(X),(Y)(X)属于(Y),则(X=Y)
    引理4:如果有两个环(X),(Y)(e)属于(X)(Y)的交集,则存在一环(c)属于(X+Y-e)
    引理5:令(I)是拟阵的一个基,如果(x)元素不属于(I),则(I+x)只有一个环子集
    拟阵上的最优化:
    把所有元素从大到小排序后,能加就加,不形成环就加入。
    可以证明正确性
    秩函数:定义一个拟阵的秩为拟阵的一个极大独立集(U)的大小
    引理6:对于所有在拟阵中的(U)(0leq r(U)leq card(U))
    引理7:对于任意集合(A)属于(B)属于(S)(r(A)leq r(B))
    引理8:对于任意集合(A,Bsupset S)(r(Acup B)+r(Acap B)leq r(A)+r(B))
    拟阵交:
    给定两个拟阵,求他们的(U)值的交的最大(权)独立集
    考虑增量法。
    每次从一个答案为(X)的集合到答案为(X+1)的集合。
    考虑一个二分图:把元素看作一个点。
    左边表示已经被拓展的集合(A),右边表示未被拓展的集合(B)
    左边(a)向右边(b)连有向边,只有(A-a+b)是独立集
    右边(b)向左边(a)连有向边,只有(B-b+a)是独立集
    找到集合(C,D)(C)是满足以下条件的点集合:
    (A+x)满足第一个拟阵的条件,(x)(C)
    (A+y)满足第二个拟阵的条件,(y)(D)中。
    (C->D)的最短路,把最短路上元素的选择状态反转就是答案。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1010
    int d[N],pr[N],v1[N],v2[N],n,m,x[N],y[N],z[N],f[N],k,c[N],v3[N],v4[N],tc[N];
    vector<int>v[N];
    int fd(int x){
    	return f[x]==x?x:f[x]=fd(f[x]);
    }
    int bfs(){
    	queue<int>q;
    	for(int i=0;i<=m;i++){
    		d[i]=1e9;
    		pr[i]=0;
    	}
    	for(int i=1;i<=m;i++)
    		if(v3[i]){
    			q.push(i);
    			d[i]=0;
    		}
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		for(int y:v[x])
    			if(d[y]>d[x]+1){
    				d[y]=d[x]+1;
    				q.push(y);
    				pr[y]=x;
    			}
    	}
    	int ans=0;
    	for(int i=1;i<=m;i++)
    		if(v4[i]&&d[ans]>d[i])
    			ans=i;
    	if(d[ans]>1e8)
    		return 0;
    	return ans;
    }
    int main(){
    	freopen("forget.in","r",stdin);
    	freopen("forget.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&k);
    	for(int i=1;i<=k;i++)
    		scanf("%d",&c[i]);
    	for(int i=1;i<=m;i++)
    		scanf("%d%d%d",&x[i],&y[i],&z[i]);
    	for(int i=1;i<=m;i++)
    		v2[i]=1;
    	int ans=0;
    	for(int i=1;i<n;i++){
    		for(int j=1;j<=m;j++)
    			v[j].clear();
    		for(int j=1;j<=m;j++)
    			if(v1[j]){
    				for(int l=1;l<=n;l++)
    					f[l]=l;
    				for(int l=1;l<=m;l++)
    					if(v1[l]&&l!=j){
    						int xx=fd(x[l]),yy=fd(y[l]);
    						if(xx!=yy)
    							f[xx]=yy;
    					}
    				for(int l=1;l<=m;l++)
    					if(v2[l]){
    						int xx=fd(x[l]),yy=fd(y[l]);
    						if(xx!=yy)
    							v[j].push_back(l);
    					}
    			}
    		for(int j=1;j<=m;j++)
    			if(v2[j]){
    				for(int l=1;l<=m;l++)
    					if(v1[l]){
    						tc[z[l]]--;
    						if(tc[z[j]]<c[z[j]])
    							v[j].push_back(l);
    						tc[z[l]]++;
    					}
    			}
    		for(int j=1;j<=n;j++)
    			f[j]=j;
    		for(int j=1;j<=m;j++)
    			if(v1[j]){
    				int xx=fd(x[j]),yy=fd(y[j]);
    				if(xx!=yy)
    					f[xx]=yy;
    			}
    		for(int j=1;j<=m;j++){
    			if(v2[j]&&fd(x[j])!=fd(y[j]))
    				v3[j]=1;
    			else
    				v3[j]=0;
    			if(v2[j]&&tc[z[j]]<c[z[j]])
    				v4[j]=1;
    			else
    				v4[j]=0;
    		}
    		int po=bfs(),ok=0;
    		if(!po)
    			break;
    		ans=i;
    		while(po){
    			if(!ok){
    				v2[po]=0;
    				v1[po]=1;
    				tc[z[po]]++;
    			}
    			else{
    				v2[po]=1;
    				v1[po]=0;
    				tc[z[po]]--;
    			}
    			ok^=1;
    			po=pr[po];
    		}
    	}
    	printf("%d
    ",m-ans);
    	for(int i=1;i<=m;i++)
    		if(v2[i])
    			printf("%d ",i);
    }
    
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 阿尔法乘积
    Java实现 蓝桥杯VIP 算法训练 黑色星期五
    Java实现 蓝桥杯VIP 算法训练 黑色星期五
    Java实现 蓝桥杯VIP 算法训练 阶乘
    Java实现 蓝桥杯VIP 算法训练 反置数
    Java实现 蓝桥杯VIP 算法训练 新生舞会
    Android消息机制架构和源码解析
    华为接班人制度(效率优先,兼顾公平,可持续发展)
    VMware与宿敌Amazon一笑泯恩仇:重新定义混合云?(私有云节节败退)
    UAC新解(有非正常手段可以绕过)
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14319648.html
Copyright © 2020-2023  润新知