poj2987 求最大权闭合回路

建图差不多和以前做的差不多,就是最后询问这个闭合子图有多少个的时候,只要输出这个图的S集合,就是进行dfs能遍历到的点一定在S集合中,不能遍历到的点在T集合中

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn=5555;
const long long INF=1LL<<60;
typedef long long LL;
struct Dinic
{

    struct Edge{
      LL from,to,cap,flow;
      Edge(LL cfrom=0,LL cto=0,LL ccap=0,LL cflow=0)
      {
          from=cfrom;  to=cto; cap=ccap; flow=cflow;
      }
    };
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n)
    {
        m=0;
        this->n=n;
        for(int i=0; i<=n; i++)G[i].clear();
        edges.clear();
    }
    void addEdge(LL from,LL to, LL cap)
    {
        edges.push_back(Edge(from,to,cap,0) );
        edges.push_back(Edge(to,from,0,0));
        m+=2;
        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]==false&&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]];
            LL  dd =min(a,e.cap-e.flow);
            if(d[x]+1==d[e.to]&&(f=DFS(e.to,dd))>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;
    }
    void find(int cur)
    {
        vis[cur]=true;
        for(int i=0; i<G[cur].size(); i++)
        {
            Edge &e=edges[G[cur][i]];
            if(vis[e.to]||e.cap<=e.flow)continue;
            find(e.to);
        }
    }
    int solve()
    {
        memset(vis,0,sizeof(vis));
        for(int i=0; i<G[s].size(); i++)
        {
            Edge &e=edges[G[s][i]];
            if(vis[e.to]||e.cap<=e.flow)continue;
            find(e.to);
        }
        int ans=0;
        for(int i=1; i<=n-2; i++)
            ans+=vis[i];
        return ans;
    }
}T;
int P[maxn];
int main()
{
     int n,m;
     while(scanf("%d%d",&n,&m)==2)
     {
         LL S1=0,S2=0;
         T.init(n+2);
         for(int i=1; i<=n; i++)
         {
             scanf("%d",&P[i]);
             if(P[i]>0){
                S1+=P[i];S2+=P[i];
                T.addEdge(n+1,i,P[i]);
             }else{
                S1+=-P[i];
                T.addEdge(i,n+2,-P[i]);
             }
         }
         for(int i=1; i<=m; i++)
         {
             int a,b;
             scanf("%d%d",&a,&b);
             T.addEdge(a,b,S1);
         }
         LL a1=T.Maxflow(n+1,n+2);
         LL a2=T.solve();
         printf("%I64d %I64d\n",a2,S2-a1);
     }
     return 0;
}

时间: 2024-10-12 09:25:09

poj2987 求最大权闭合回路的相关文章

HDU 5045 费用流求最大权

点击打开链接 题意:有n个人和m到题目,每个人做对的概率以矩阵形式给出,问如何分配才可以使做对的概率最大,有一个限制条件是做到目前为止每两个人的做题数量差距不能超过1,也就是前n道题目,必须一人做一个 思路:网上都是dp多一点,用网络流也可以,不过麻烦很多,可是本弱是一点dp都不会的选手啊,只能用网络流了,对于那个限制条件,我们可以以前n道题建一次图,然后再来n个,不过就直接建完就可以了,然后我们要求的是什么呢,很明显是最大权,而最大费用最大流刚好可以解决,这里面的费用流有两种方法,用spfa找

网络流——最小割求最大权闭合子图

定义 有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图. 如下图:  能选的子图有?,{4},{3,4},{2,4},{1,2,3,4},它们的权值分别为0,-1,5,-6,4. 所以最大权闭合子图为{3,4},权值为5. 解法 这个问题可以转化为最小割问题,用网络流解决. 从源点s向每个正权点连一条容量为权值的边,每个负权点向汇点t连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大.  求它的最

二分图最佳匹配,求最大权匹配或最小权匹配

Beloved Sons http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1338 题意:国王有N个儿子,现在每个儿子结婚都能够获得一定的喜悦值,王子编号为1-N,有N个女孩的编号同样为1-N,每个王子心中都有心仪的女孩,现在问如果安排,能够使得题中给定的式子和最大. 分析:其实题目中那个开根号是个烟雾弹,只要关心喜悦值的平方即可.那么对王子和女孩之间构边,边权为喜悦值的平方,对于每一个王子虚拟出一个女孩边权为0,这样是为了所

Prim算法求最大权,POJ(2485)

题目链接:http://poj.org/problem?id=2485 解题报告: #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; #define NUM 1000 const int maxint=10000000; int c[NUM][NUM]; ///邻接矩阵 int ans=maxint; int

POJ2987 Firing 最大权闭合图

详情请参考http://www.cnblogs.com/kane0526/archive/2013/04/05/3001557.html 值得注意的地方,割边会把图分成两部分,一部分和起点相连,另一部分和汇点相连 我们只需要关注和起点相连的点的点就好,如何统计呢? 只需要从起点开始搜索,只要边不是满流,一直搜就好 然后,答案就是总权值-最小割 注:对于dinic网络流,我还是喜欢LRJ白书上的,用起来方便 #include <cstdio> #include <cstdlib> #

poj2987--Firing(最大权闭合图)

poj2987:题目链接 题目大意:有个公司,n个员工,m个关系,因为亏损,所以要辞退一些员工,给出辞退每个员工会给带来的收益(有正有负),关系x y代表x是y的上司,如果辞退一个上司,那么他手下的人都会退出,问最大的收益,和要删除的人数. 因为删掉一个上司,员工也会离开,所以最后求的删除的人会是一个闭合图,也就是求最大权闭合图,将其中正值k的点i连接边<s,i>值为正,原图中的边值为正无穷,负值k的点j连接边<j,t>值为-k,这样求得最小割,也就是一个简单割,其中s集合所在的点

算法笔记_139:二分图的最大权分配(Java)

目录 1 问题描述 2 解决方案   1 问题描述 何为二分图的最大权匹配问题? 最大权二分匹配问题就是给二分图的每条边一个权值,选择若干不相交的边,得到的总权值最大. 2 解决方案 对于此问题的讲解,引用文末参考资料1: 解决这个问题可以用KM算法.理解KM算法需要首先理解"可行顶标"的概念.可行顶标是指关于二分图两边的每个点的一个值lx[i]或ly[j],保证对于每条边w[i][j]都有lx[i]+ly[j]-w[i][j]>=0.如果所有满足lx[i]+ly[j]==w[i

HDU5772 String problem 最大权闭合图+巧妙建图

题意:自己看吧(不是很好说) 分析: 网络流:最大权闭合子图. 思路如下: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点

hdu 2255 二分图最大权匹配 *

题意:说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子.另 一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格, 比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出2