zoukankan      html  css  js  c++  java
  • 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
    ",ans>0?-ans:0);return 0;
    50 }
    最大权闭合子图
  • 相关阅读:
    Git安装及密钥的生成并上传本地文件到GitHub上
    进阶攻略|前端最全的框架总结
    进阶攻略|前端最全的框架总结
    干货|几个有用的问答平台
    干货|几个有用的问答平台
    美食篇之御桥小聚
    美食篇之御桥小聚
    Java EE (8) -- Java EE Patterns
    css---position、z-index、opacity、overflow、hover、background
    T1082 线段树练习3 codevs
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10255651.html
Copyright © 2011-2022 走看看