POJ 2987 Firing 最大全闭合图(输出删除点后权最大)

题意公司要裁员,每个员工被裁掉之后都会有一定的收益(正或者负),有一些员工之间有限制关系,就是裁掉谁之前必须要先裁掉另一个人,问公司的最大收益和最大收益前提下的最小裁员人数?(copy题意)


想法:一看就是最大权闭合,直接可以算出最大的收益,关键是输出最小的裁员人数,可以从残余网络里面去找,当残余网络里面的一条边,有正的权值时说明了两种可能,一种是source->(+a)的边权大于零,表示我不要这个人可以赚钱,所以a和他相连的都要开除,(-a)->sink的边权大于零,表示a可以赚很多钱以保证我不开除他的上司,我也可以赚钱。

还有一个就是建边的问题,我是这样理解的,a的前提是b那么b就是删除a的基础,那么a的地位显然比b要重要,所以a->b。

#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#define inf 0x7fffffff
using namespace std;
const int N=50000+20;
const int M=60000+20;
int n,m,val[N];
long long sum;
int s,t,num;
int vis[N];
struct node
{
	int v,next;
	int flow;
}e[M*2];
int head[N],cnt;
class DINIC
{
	public:
		int spath()
		{
			queue<int>q;
			while(!q.empty()) q.pop();
			memset(dis,-1,sizeof(dis));
			dis[s]=0;
			q.push(s);
			while(!q.empty())
			{
				int u=q.front();
				q.pop();
				for(int i=head[u];i+1;i=e[i].next)
				{
					int v=e[i].v;
					if(dis[v]==-1&&e[i].flow>0)
					{
						dis[v]=dis[u]+1;
						q.push(v);
					}
				}
			}
			return dis[t]!=-1;
		}
		int MIN(int x,int y)
		{
			if(x<y) return x;
			return y;
		}
		int dfs(int u,int flow)
		{
			if(u==t) return flow;
			int cost=0;
			for(int i=head[u];i+1;i=e[i].next)
			{
				int v=e[i].v;
				if(dis[v]==dis[u]+1&&e[i].flow>0)
				{
					int mmin=dfs(v,MIN(e[i].flow,flow-cost));
					if(mmin>0)
					{
						e[i].flow-=mmin;
						e[i^1].flow+=mmin;
						cost+=mmin;
						if(flow==cost) break;
					}
					else dis[v]=-1;
				}
			} 
			return cost;
		}
		long long result()
		{
			long long res=0;
			while(spath())
			{
				res+=dfs(s,inf);
			}
			return res;
		}
	private:
		int dis[N];
}dinic;
void qianxiang_Init()
{
	memset(head,-1,sizeof(head));
	cnt=0;
}
void add(int a,int b,int c)
{
	e[cnt].v=b;
	e[cnt].flow=c;
	e[cnt].next=head[a];
	head[a]=cnt++;
	
	e[cnt].v=a;
	e[cnt].flow=0;
	e[cnt].next=head[b];
	head[b]=cnt++;
}
void Input()
{
	for(int i=1;i<=n;i++)
	scanf("%d",&val[i]); 
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d %d",&a,&b);
		add(a,b,inf);
	}
}
void dfs(int u)
{
	if(u==t) return;
	vis[u]=1;
	for(int i=head[u];i+1;i=e[i].next)
	{
		int v=e[i].v;
		if(!vis[v]&&e[i].flow>0)
		{
			num++;
			dfs(v);
		}
	}
	return;
}
void build_map()
{
	s=0;t=n+1;
	sum=0;
	for(int i=1;i<=n;i++)
	{
		if(val[i]>=0) 
		{
		    add(s,i,val[i]);
		    sum+=val[i];
		}
		else add(i,t,-val[i]);
	}
}
void treatment()
{
	build_map();
	long long profit=dinic.result();
	num=0;
	memset(vis,0,sizeof(vis));
	dfs(s);
	printf("%d %lld\n",num,sum-profit);
}
int main()
{
	while(~scanf("%d %d",&n,&m))
	{
		qianxiang_Init();
		Input();
		treatment();
	}
	return 0;
} 



你可能感兴趣的:(想法题)