【dinic求最大权闭合子图】课程开发计划

xiaoxiao2021-02-28  47

首先get知识点讲解(活动和邀请学生的题,主要看如何建图的和结论!很重要!):

https://blog.csdn.net/Cold_Chair/article/details/52841351

结论:最大权闭合子图 = 正点和-最小割。(同时,如果题目要求不仅要是最大权,并且要求"活动"点数还最少,那代码不用变,照样满足。

这种题型都是直接套这个结论即可。

大致思路

就是用结论“正点和-最小割=最大权闭合子图”

建图如下:

代码

[cpp]  view plain  copy #include<cstdio>  #include<cstring>  #include<algorithm>  #include<queue>  #define maxn 5010  #define maxm 50100  #define inf 0x3f3f3f3f  using namespace std;  struct Edge{      int v,c,next;      Edge(int v,int c,int next):v(v),c(c),next(next){}      Edge(){}  }e[maxm*6+maxn*2];  int p[maxn+maxm];  int cnt,n,m,T;  void init(){      cnt=0;      memset(p,-1,sizeof(p));  }  void insert(int u,int v,int c){      e[cnt]=Edge(v,c,p[u]);      p[u]=cnt++;  }  int d[maxn+maxm];  bool bfs(){      memset(d,-1,sizeof(d));      queue<int>q;      d[0]=0;      q.push(0);      while(!q.empty()){          int u=q.front();q.pop();          for(int i=p[u];i!=-1;i=e[i].next){              int v=e[i].v;              if(e[i].c>0&&d[v]==-1){                  //printf("%d->%d(%d)\n",u,v,d[u]+1);                  d[v]=d[u]+1;                  q.push(v);              }          }      }      return d[T]!=-1;  }  int dfs(int u,int flow){      if(u==T)return flow;      int res=0;      for(int i=p[u];i!=-1;i=e[i].next){          int v=e[i].v;          if(e[i].c>0&&d[v]==d[u]+1){              int tmp=dfs(v,min(flow,e[i].c));              e[i].c-=tmp;              flow-=tmp;              e[i^1].c+=tmp;              res+=tmp;              if(flow==0)                  break;          }      }      if(res==0)          d[u]=-1;      return res;  }  int dinic(){      int res=0;      while(bfs()){     //     printf("here!\n");          res+=dfs(0,inf);      }      return res;  }  int main(){      init();      int p,a,b,c,sum=0;      scanf("%d%d",&n,&m);      T=n+m+1;//汇点      for(int i=1;i<=n;i++){          scanf("%d",&p);          insert(i+m,T,p);  //课程放右边        insert(T,i+m,0);      }      for(int i=1;i<=m;i++){          scanf("%d%d%d",&a,&b,&c);          sum+=c;          insert(i,a+m,inf);           insert(a+m,i,0);          insert(i,b+m,inf);          insert(b+m,i,0);          insert(0,i,c);   //用户放左边        insert(i,0,0);      }      printf("%d\n",sum-dinic());      return 0;  }  
转载请注明原文地址: https://www.6miu.com/read-2626761.html

最新回复(0)