您的位置:首页 > 其它

poj 2987 Firing 最大权闭合子图

2017-02-14 22:46 726 查看
参见文献:

最小割模型在比赛中的运用

这是最大权闭合子图问题,参见以上文献.

建边,

s->i if b[i]>0;

i->t if b[i]<0;

i->j if j是i的下属

费用就等于

∑b[i]>0b[i]−max−flow

与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 0x3f3f3f3f3f3f3f3f
using 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();

4000
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最大权闭合子图