HOJ 2634 最大权闭合子图

来源:互联网 发布:泰国地图导航软件 编辑:程序博客网 时间:2024/05/16 17:48

最大权闭合子图指的是对于n个点,选择每个点都必须选择其子结点,然后其子结点连接过去的箭头的全部点也必须选,

每个点有其自己的权值,有正也有负,问如何选子图可以使得权值和相加最大。

就有一个算法,把所有点权值为正的相加为sum,然后建立一个源点s,连接全部权值为正的点,再建立一个汇点,由权值为负的点指向,跑一遍最大流(最小割)

sum-最大流结果=最大权闭合子图

#include<cstdio> #include<cstring> #include<queue> #include<cmath> #include <iostream> using namespace std; const int Ni = 210; const int MAX = 1<<26; struct Edge{     int u,v,c;     int next; }edge[20*Ni]; int n,m; int edn;//边数 int p[Ni];//父亲 int d[Ni]; int sp,tp;//原点,汇点 void addedge(int u,int v,int c) {     edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;     edge[edn].next=p[u]; p[u]=edn++;     edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;     edge[edn].next=p[v]; p[v]=edn++; } int bfs() {     queue <int> q;     memset(d,-1,sizeof(d));     d[sp]=0;     q.push(sp);     while(!q.empty())     {         int cur=q.front();         q.pop();         for(int i=p[cur];i!=-1;i=edge[i].next)         {             int u=edge[i].v;             if(d[u]==-1 && edge[i].c>0)             {                 d[u]=d[cur]+1;                 q.push(u);             }         }     }     return d[tp] != -1; } int dfs(int a,int b) {     int r=0;     if(a==tp)return b;     for(int i=p[a];i!=-1 && r<b;i=edge[i].next)     {         int u=edge[i].v;         if(edge[i].c>0 && d[u]==d[a]+1)         {             int x=min(edge[i].c,b-r);             x=dfs(u,x);             r+=x;             edge[i].c-=x;             edge[i^1].c+=x;         }     }     if(!r)d[a]=-2;     return r; } int dinic(int sp,int tp) {     int total=0,t;     while(bfs())     {         while(t=dfs(sp,MAX))         total+=t;     }     return total; } int main() { //freopen("in.txt","r",stdin);     int i,u,j,v,c;     int T;     int t1,t2,t3,t4;     scanf("%d",&T);     while(~scanf("%d%d",&n,&m))     {         edn=0;//初始化         memset(p,-1,sizeof(p));         sp=0;tp=m+n+1;        int sum=0;        for(i=1;i<=n;i++){            scanf("%d",&t1);         //   cout  << "0 到 " << i <<"花费为 " <<t1<< endl;            addedge(0,i,t1);            sum+=t1;        }        //cout << sum << endl;        for(i=1;i<=m;i++){            scanf("%d",&t1);       //     cout  << i+n<<" 到 " << tp <<"花费为 " <<t1<< endl;            addedge(i+n,tp,t1);        }        for(i=1;i<=n;i++){            scanf("%d",&t1);            for(j=1;j<=t1;j++){                scanf("%d",&t2);t2++;              //  cout <<i <<" ---" << t2 <<endl;                addedge(i,n+t2,MAX);            }        }      //  cout << dinic(sp,tp) << endl;         printf("%d\n",sum-dinic(sp,tp));     }     return 0; }