总觉得在大考前学习新知识点不太好。
模拟赛考了一道拟阵交。。。。。
拟阵是一个集合的集合(二元组((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);
}