• poj2987 Firing 最大权闭合子图 边权有正有负


    /**
    题目:poj2987 Firing 最大权闭合子图 边权有正有负
    链接:http://poj.org/problem?id=2987
    题意:由于金融危机,公司要裁员,如果裁了员工x,那么x的下级都要裁掉,如果x的下级被裁掉,那么x的下级的下级也要裁掉。。。依次类推
    每个员工有个价值,公司裁了员工i,获得价值wi(有正有负),
    问公司如何裁员获得最大价值。输出裁员人数以及最大价值。
    思路:最大权闭合子图。如果员工x价值wx为正,s->x,cap=wx; 如果员工y价值为wx为负,x->t,cap=-wx;
    如果员工x是y的上级,x->y,cap=INF;
    求s-t最大流,结果为所有正价值之和-最大流。
    或者:
    求s-t最大流之后,此时dinic的vis为1的点表示在该最小割的S集合内。S集合除去s点的其他点就是需要裁员的人,从中可以获取人数,以及计算价值和。
    
    新增附加源s和附加汇t,从s向所有的正权点引一条边,容量为权值;从所有的负权点向汇点引一条边,容量为负权的相反数。求出最小割以后,S-{s}就是最大闭合子图。
    */ #include<iostream> #include<cstring> #include<vector> #include<map> #include<cstdio> #include<sstream> #include<algorithm> #include<queue> using namespace std; typedef long long LL; const int INF = 0x3f3f3f3f; const int N = 5005; struct Edge{ int from, to, cap, flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct Dinic{ int n, m, s, t; vector<Edge> edges; vector<int> G[N]; bool vis[N]; LL d[N]; int cur[N]; void init(int n) { this->n = n; for(int i = 0; i <= n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BFS(){ memset(vis, 0, sizeof vis); queue<int> Q; Q.push(s); d[s] = 0; vis[s] = 1; while(!Q.empty()){ int x = Q.front(); Q.pop(); for(int i = 0; i < G[x].size(); i++){ Edge &e = edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to] = 1; d[e.to] = d[x]+1; Q.push(e.to); } } } return vis[t]; } LL DFS(int x,LL a){ if(x==t||a==0) return a; LL flow = 0, f; for(int &i = cur[x]; i < G[x].size(); i++){ Edge& e = edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,(LL)e.cap-e.flow)))>0){ e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a==0) break; } } return flow; } LL Maxflow(int s,int t){ this->s = s, this->t = t; LL flow = 0; while(BFS()){ memset(cur, 0, sizeof cur); flow += DFS(s,INF); } return flow; } }; int main() { int n, m; while(scanf("%d%d",&n,&m)==2) { int s = 0, t = n+1; Dinic dinic; dinic.init(t); int w; LL sum = 0; for(int i = 1; i <= n; i++){ scanf("%d",&w); if(w>=0){ sum += w; dinic.AddEdge(s,i,w); }else dinic.AddEdge(i,t,-w); } int u, v; for(int i = 1; i <= m; i++){ scanf("%d%d",&u,&v); dinic.AddEdge(u,v,INF); } LL flow = dinic.Maxflow(s,t); int num = 0; for(int i = 1; i <= n; i++){ if(dinic.vis[i]){ num++; } } printf("%d %lld ",num,sum-flow); } return 0; }
  • 相关阅读:
    HDU 5409 CRB and Graph (边双连通+DFS)
    HDU 3749 Financial Crisis (点双连通+并查集)
    POJ 1523 SPF (无向图割点)
    HDU 3639 Hawk-and-Chicken (强连通缩点+DFS)
    UVA11324 The Largest Clique (强连通缩点+DP最长路)
    HDU 3861 The King’s Problem (强连通缩点+DAG最小路径覆盖)
    ZOJ 3795 Grouping (强连通缩点+DP最长路)
    POJ 2455 Secret Milking Machine 【二分】+【最大流】
    POJ 2112 Optimal Milking (二分+最短路+最大流)
    POJ 1094 Sorting It All Out 【拓扑排序】
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7227268.html
Copyright © 2020-2023  润新知