正值点为S集,负值点为T集,源点s连接S集,T集连接汇点t;
建立二分图,求最大流,用正值的和减去最小割(最大流),即为所求
正值点代表开除,负值点代表 不被开除。如果有通路,则表示上司被开除,但下属没被开除,显然不成立,所以要求最小割,即最大流
画图感受一下吧!!
这题一些定义要用long long,不然会wa
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
long long n,ans,res,sum;
int ff[5050];
int d[5050];
struct node
{
int b;
long long len;
};
int flag;
vector<int> f[130000];
vector<node> edge;
bool bfs() //bfs 分层
{
memset(d,-1,sizeof(d));
d[0]=0;
queue<int> q;
q.push(0);
while(!q.empty()){
int u=q.front();
q.pop();
int l=f[u].size();
for(int i=0;i<l;i++){
if(edge[f[u][i]].len > 0 && d[edge[f[u][i]].b]<0){
d[edge[f[u][i]].b]=d[u]+1;
q.push(edge[f[u][i]].b);
}
}
}
if(d[n+1]>0) return 1;
else return 0;
}
long long dfs(int s,long long max)//dfs处理
{
long long i,a;
if(s==n+1 || max==0) return max;
int l=f[s].size();
long long dt=max;
for(i=0;i<l;i++){
if(edge[f[s][i]].len > 0 && d[s]+1==d[edge[f[s][i]].b] &&( a=dfs(edge[f[s][i]].b,min(dt,edge[f[s][i]].len))) ){
edge[f[s][i]].len -= a;
edge[f[s][i]^1].len += a;
dt-=a;
if(dt==0) break;
}
}
return max-dt;
}
void dfs1(int s) //找被开除的人数
{
int l=f[s].size();
for(int i=0;i<l;i++){
if(edge[f[s][i]].len > 0 && ff[edge[f[s][i]].b]==0)
{
flag++;
ff[edge[f[s][i]].b]=1;
dfs1(edge[f[s][i]].b);
}
}
}
int main()
{
int i,j,k;
int m;
node w;
while(scanf("%d%d",&n,&m)!=EOF){
sum=0;
for(i=0;i<=n+1;i++)
f[i].clear();
edge.clear();
for(i=1;i<=n;i++)
{
long long t;
scanf("%lld",&t);
if(t>=0){
sum+=t;
w.b=i;
w.len=t;
edge.push_back(w);//存正向边
w.b=0;
w.len=0;
edge.push_back(w);//存反向边,反向边赋值为0
int tt=edge.size();
f[0].push_back(tt-2);
f[i].push_back(tt-1);
}
else{
w.b=n+1;
w.len=-t;
edge.push_back(w);
w.b=i;
w.len=0;
edge.push_back(w);
int tt=edge.size();
f[i].push_back(tt-2);
f[n+1].push_back(tt-1);
}
}
for(i=1;i<=m;i++)
{
int a,c;
scanf("%d%d",&a,&c);
w.b=c;
w.len=999999999999;
edge.push_back(w);
w.b=a;
w.len=0;
edge.push_back(w);
int tt=edge.size();
f[a].push_back(tt-2);
f[c].push_back(tt-1);
}
ans=0,res=0;
flag=0;
while(bfs()){ //dinic算法
while(res=dfs(0,999999999999)){
ans += res;
}
}
memset(ff,0,sizeof(ff));
ff[0]=1;
dfs1(0);//找被开除的人的个数,处理完的图,能走到的点,就是被开除人的个数
printf("%d %lld\n",flag,sum-ans);
}
return 0;
}