51nod 1551 集合交易 最大权闭合子图

题意:

  市场中有n个集合在卖。我们想买到满足以下要求的一些集合,所买到集合的个数要等于所有买到的集合合并后的元素的个数。

  每个集合有相应的价格,要使买到的集合花费最小。

  这里我们的集合有一个特点:对于任意整数k(k>0),k个集合的并集中,元素的个数不会小于k个。

  现在让你去市场里买一些满足以上条件集合,可以一个都不买。

分析:

  根据集合的特点,我们发现,如果吧集合和元素分成左右部,建出二分图,那么一定存在完美匹配。

  所以我们把一个集合匹配的那个元素当成它的代表元素。

  我们要求最终买到的集合个数要等于并集元素个数。

  所以我们如果选择了一个集合,这个集合中除了它的代表元素(设为x),假如还有y元素,而y元素恰好是另一个集合的代表元素,那么我们选择了x代表的集合,就必须选择y代表的那个集合。

  这就是最大权闭合子图的模型,选择一个就必须选择另一个。

  于是我们把图建出来,根据题目的性质,最后的花费一定不是正数(因为我们可以1个也不选啊),所以当能赚价值的时候,我们就赚,不能赚,我们就一个也不要。

代码:

 1 #include<bits/stdc++.h>
 2 #define ms(a,x) memset(a,x,sizeof(a))
 3 using namespace std;int S,T;bool a[500][500];
 4 const int N=305,M=200000,inf=999999999;
 5 struct node{int y,z,nxt;}e[M];int q[M],tot;
 6 int o=1,h[N],c[N],d[N],m,k,n,ans;bool b[N];
 7 void add(int x,int y,int z){
 8     e[++o]=(node){y,z,h[x]};h[x]=o;
 9     e[++o]=(node){x,0,h[y]};h[y]=o;
10 } bool bfs(){int f=1,t=0;ms(d,-1);
11     d[S]=0;q[++t]=S;
12     while(f<=t){
13         int x=q[f++];
14         for(int i=h[x],y;i;i=e[i].nxt)
15         if(d[y=e[i].y]==-1&&e[i].z)
16         d[y]=d[x]+1,q[++t]=y;
17     } return (d[T]!=-1);
18 } int dfs(int x,int f){
19     if(x==T) return f;int w,tmp=0;
20     for(int i=h[x],y;i;i=e[i].nxt)
21     if(d[y=e[i].y]==d[x]+1&&e[i].z){
22         w=dfs(y,min(e[i].z,f-tmp));
23         if(!w) d[y]=-1;e[i].z-=w;
24         e[i^1].z+=w;tmp+=w;if(tmp==f) return f;
25     } return tmp;
26 } void solve(){
27     while(bfs()) tot+=dfs(S,inf);
28 } bool hun(int x){
29     for(int i=1;i<=n;i++)
30     if(a[x][i]&&!b[i]){ b[i]=1;
31         if(!c[i]||hun(c[i]))
32         {c[i]=x;return 1;}
33     } return 0;
34 } int main(){ tot=ans=0;
35     scanf("%d",&n);S=0;T=n+1;
36     for(int i=1,x,p;i<=n;i++){
37         scanf("%d",&p);
38         while(p--) scanf("%d",&x),a[i][x]=1;
39     } for(int i=1;i<=n;i++) ms(b,0),hun(i);
40     for(int i=1;i<=n;i++)
41     for(int j=1;j<=n;j++)
42     if(a[i][j]&&c[j]!=i)
43     add(i,c[j],inf);
44     for(int i=1,x;i<=n;i++){
45         scanf("%d",&x);x=-x;
46         if(x<0) add(i,T,-x);
47         else add(S,i,x),ans+=x;
48     } solve();ans-=tot;
49     printf("%d\n",ans>0?-ans:0);return 0;
50 }
最大权闭合子图

猜你喜欢

转载自www.cnblogs.com/Alan-Luo/p/10255651.html