poj 2987 Firing 最大权闭合子图

来源:互联网 发布:在线格式化sql语句 编辑:程序博客网 时间:2024/05/22 13:12

参见文献:
最小割模型在比赛中的运用

这是最大权闭合子图问题,参见以上文献.
建边,
s->i if b[i]>0;
i->t if b[i]<0;
i->j if j是i的下属
费用就等于
b[i]>0b[i]maxflow
S相连接的点为裁掉的人员

#include <cstdio>#include <iostream>#include <vector>#include <queue>#include <algorithm>#include <cmath>#include <cstring>#include <map>#include <set>#include <stack>#define fi first#define se second#define INF 0x3f3f3f3f#define INF64 0x3f3f3f3f3f3f3f3fusing namespace std;typedef long long LL;typedef pair<int,int> Pair;const int maxn = 5000+10;const int MAX_V = 5000+10;struct Edge{  int from,to;//原图的边  LL cap;  Edge(int u,int v,LL c = 0):from(u),to(v),cap(c){};};std::vector<Edge> E;std::vector<int> G[MAX_V];//残量网络void add_edge(int u,int v,LL cap){  E.push_back(Edge(u,v,cap));G[u].push_back(E.size()-1);  E.push_back(Edge(v,u,0));  G[v].push_back(E.size()-1);}struct Dinic{  int level[MAX_V],cur[MAX_V];//分层,当前弧;  void bfs(int s){    memset(level,-1,sizeof(level));    queue<int> Q;Q.push(s);    level[s] = 0;    while (!Q.empty()) {      int u = Q.front();Q.pop();      for(int i=0 ; i<G[u].size() ; ++i){        Edge & e = E[G[u][i]];        if(e.cap>0 && level[e.to]<0){          level[e.to] = level[u]+1;          Q.push(e.to);        }      }    }  }  LL dfs(int v,int t,LL f){    if(v==t || f == 0)return f;    for(int& i = cur[v] ; i<G[v].size() ; ++i){      Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];      if(e.cap>0 && level[v]<level[e.to]){        LL a = dfs(e.to,t,min(f,e.cap));        if(a>0){          e.cap-=a;          rev.cap+=a;          return a;        }      }    }    return 0;  }  LL max_flow(int s,int t){    LL flow = 0;    for(;;){      bfs(s);      if(level[t]<0)break;      memset(cur,0,sizeof(cur));      LL f;      while ((f = dfs(s,t,INF64))>0) {        flow+=f;      }    }    return flow;  }};LL b[maxn];Dinic Flow;bool mark[MAX_V];int cnt =0;void dfs(int s){  mark[s] = true;cnt++;  for(int i=0 ; i<G[s].size() ; ++i){    Edge & e = E[G[s][i]];    if( e.cap>0&& !mark[e.to])dfs(e.to);  }}int main() {  int n,m;  scanf("%d%d",&n,&m );    for(int i=1 ; i<=n ; ++i)scanf("%lld",&b[i] );    while (m--) {      int x,y;      scanf("%d%d",&x,&y );      add_edge(x,y,INF64);    }    int s = 0,t = n+1;    LL sum = 0;    for(int i=1 ; i<=n ; ++i)    {        if(b[i]>0){add_edge(s,i,b[i]);sum+=b[i];}        else add_edge(i,t,-b[i]);    }    LL profit = sum-Flow.max_flow(s,t);    memset(mark,false,sizeof(mark));    cnt = 0;    dfs(s);    printf("%d %lld\n",--cnt,profit );  return 0;}
0 0
原创粉丝点击