题型:网络流
题意:
公司裁员,裁掉一个员工,会赚入或亏损。员工之间用上下级关系,裁掉一个员工,就要裁掉他的下级。要求裁员后赚钱最多,求裁掉的员工数和最多的收入。
分析:
采用最大权闭合图来建模,利用最大流求解。
源点与正权员工建边,权值为裁掉该员工可获得的收入;
上下级建边,权值为inf;
负权员工与汇点建边,权值为裁掉该员工的亏损值;
最多收入等于正权值之和减去最大流。
跑完最大流之和,从源点S开始dfs残留网络,有剩余流量的边所属的点,即为被裁掉的员工。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define LL long long
#define mt(a,b) memset(a,b,sizeof(a))
#define PI acos(-1.0)
using namespace std;
LL value[5010];
const LL inf=0x3f3f3f3f3f3f3f3fLL;
class Dinic { ///最大流(MV^2*ME)
typedef LL typef;///流量的类型
static const int ME=1000000;///边的个数
static const int MV=5010;///点的个数
int temp[MV],cur[MV],level[MV],path[MV];
bool used[MV];
queue<int> q;
typef flow;
bool bfs(int s,int t) {
mt(level,-1);
while(!q.empty()) q.pop();
q.push(s);
level[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=g.head[u]; ~i; i=g.e[i].next) {
int v=g.e[i].v;
if(level[v]==-1&&g.e[i].flow) {
level[v]=level[u]+1;
q.push(v);
if(v==t) return true;
}
}
}
return false;
}
public:
struct G {
struct E {
int u,v,next;
typef flow;
} e[ME];
int le,head[MV];
void init() {
le=0;
mt(head,-1);
}
void add(int u,int v,typef flow) {
e[le].u=u;
e[le].v=v;
e[le].flow=flow;
e[le].next=head[u];
head[u]=le++;
}
} g;
typef getflow() {
return flow;
}
void init() {
g.init();
}
void add(int u,int v,typef flow) {
g.add(u,v,flow);
g.add(v,u,0);
}
void solve(int s,int t) {
int p,tempp;
typef now;
bool flag;
flow=0;
while(bfs(s,t)) {
for(int i=0; i<MV; i++) {
temp[i]=g.head[i];
used[i]=true;
}
p=1;
path[p]=s;
while(p) {
int u=path[p];
if(u==t) {
now=inf;
for(int i=1; i<p; i++) {
now=min(now,g.e[cur[path[i]]].flow);
}
flow+=now;
for(int i=1; i<p; i++) {
int j=cur[path[i]];
g.e[j].flow-=now;
g.e[j^1].flow+=now;
if(!g.e[j].flow) tempp=i;
}
p=tempp;
} else {
flag=false;
for(int i=temp[u]; ~i; i=g.e[i].next) {
int v=g.e[i].v;
if(used[v]&&g.e[i].flow&&level[u]+1==level[v]) {
cur[u]=i;
temp[u]=g.e[i].next;
flag=true;
path[++p]=v;
break;
}
}
if(flag) continue;
p--;
used[u]=false;
}
}
}
}
} dinic;
bool vis[5010];
void dfs(int u,int t){
if(u == t) return;
vis[u] = true;
for(int i=dinic.g.head[u];~i;i=dinic.g.e[i].next){
int v = dinic.g.e[i].v;
if(dinic.g.e[i].flow && !vis[v]){
dfs(v,t);
}
}
}
int main() {
int n,m;
while(~scanf("%d%d",&n,&m)) {
dinic.init();
///S为源点,T为汇点
///S = 0,T = n+1
int S = 0;
int T = n+1;
LL sum = 0;
for(int i=1; i<=n; i++) {
scanf("%lld",&value[i]);
if(value[i] > 0) {
dinic.add(S,i, value[i]);
sum += value[i];
} else {
dinic.add(i,T,-value[i]);
}
}
int u,v;
for(int i=0; i<m; i++) {
scanf("%d%d",&u,&v);
dinic.add(u,v,inf);
}
dinic.solve(S,T);
LL profit = dinic.getflow();
mt(vis,false);
dfs(S,T);
int person = 0;
for(int i=1;i<=n;i++)
{
if(vis[i]) person++;
}
printf("%d %lld\n",person,sum - profit);
}
return 0;
}