标签:
http://codeforces.com/problemset/problem/103/E
这道题首先一看就很像是最大权闭合子图,但是我们可以认为现在有两种点,数字和集合点,我们需要消除数字点的影响才能直接运用最大权闭合子图.
进行二分匹配,使得每个集合都唯一匹配一个数字,买下一个集合点,则意味着该集合中所有数字的对应匹配集合点都要被买下,也就是可以建立一个新图,其中某个集合点向对应数字代表的集合点连单向边,可以证明对于任意权闭合子图中的集合点,集合中所有数字的对应匹配集合点都已经在这个权闭合子图中.对这个新图的所有价格取反,答案即最大权的负数
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=305; const int maxm=2*maxn+maxn*maxn; const int sups=303,supt=304; const int inf=0x6ffffff; int n;//original aspects int price[maxn]; int st[maxn][maxn],nst[maxn]; int mch[2*maxn];//Match bool vis[2*maxn]; int first[maxn],elen;//maximum flow struct edge{ int nxt,f,t,c; }e[maxm]; int dis[maxn],gap[maxn]; bool subMatch(int s){ vis[s]=true; for(int j=0;j<nst[s];j++){ int t=st[s][j]+n; if(vis[t]||mch[t]==s)continue; if(mch[t]==0||(!vis[mch[t]]&&subMatch(mch[t]))){ mch[t]=s; mch[s]=t; return true; } } return false; } void Match(){ for(int i=1;i<=n;i++){ if(mch[i]==0){ memset(vis,false,sizeof(vis)); subMatch(i); } } } void addedge(int f,int t,int c){ e[elen].nxt=first[f]; e[elen].f=f; e[elen].t=t; e[elen].c=c; first[f]=elen++; } void build(){ for(int i=1;i<=n;i++){ if(price[i]>=0){ addedge(sups,i,price[i]); addedge(i,sups,0); } else { addedge(i,supt,-price[i]); addedge(supt,i,0); } for(int j=0;j<nst[i];j++){ int t=mch[st[i][j]+n]; addedge(i,t,inf); addedge(t,i,0); } } } int dfs(int s,int flow){ if(s==supt)return flow; int mindis=n; int tflow=flow,sub; for(int p=first[s];p!=-1;p=e[p].nxt){ int t=e[p].t; if(e[p].c>0){ if(dis[t]+1==dis[s]){ sub=dfs(t,min(tflow,e[p].c)); e[p].c-=sub;e[p^1].c+=sub; tflow-=sub; if(dis[sups]>n)return flow-tflow; if(tflow<=0)break; } mindis=min(mindis,dis[t]); } } if(flow==tflow){ --gap[dis[s]]; if(gap[dis[s]]==0)dis[sups]=n+1; else{ dis[s]=mindis+1; ++gap[dis[s]]; } } return flow-tflow; } int maxflow(){ int flow=0; gap[0]=n+2; while(dis[sups]<=n){ flow+=dfs(sups,inf); } return flow; } int main(){ int ans=0; memset(first,-1,sizeof(first)); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",nst+i); for(int j=0;j<nst[i];j++){ scanf("%d",st[i]+j); } } for(int i=1;i<=n;i++){ scanf("%d",price+i); price[i]*=-1; if(price[i]>=0)ans+=price[i]; } Match(); build(); ans=maxflow()-ans; printf("%d\n",ans); return 0; }
CF 103E Buying Sets 最大权闭合子图,匹配 难度:4
标签:
原文地址:http://www.cnblogs.com/xuesu/p/4418868.html