拟阵交 学习笔记
总觉得在大考前学习新知识点不太好。
模拟赛考了一道拟阵交。。。。。
拟阵是一个集合的集合(二元组\((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\),\(0\leq r(U)\leq card(U)\)
引理7:对于任意集合\(A\)属于\(B\)属于\(S\),\(r(A)\leq r(B)\)
引理8:对于任意集合\(A,B\supset S\),\(r(A\cup B)+r(A\cap 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\n",m-ans);
for(int i=1;i<=m;i++)
if(v2[i])
printf("%d ",i);
}