hdu4971最大权闭合图,dinic,强连通分量缩点

题意:给了n个工程,m种技术,完成某些工程可能需要先学习某些技术,完成一个工程可以得到该工程的收益,学习一种技术也要付出一定的花费,求最大收益,并且某种技术的学习可能需要先学另一种技术,并且可以相互需要,如果是相互需要则两种技术要同时学习
思路:由于技术与技术之间可能相互都有边,所以就可能存在环,可以先用强连通分量缩点,然后就可以当做DAG图来处理了,最后就可以转换为网络流模型,首先源点与各个工程之间连边,流量为该工程的收益,然后各个技术与汇点连边,流量为学习该技术的花费,然后是技术与技术之间,如果学习技术 i 要先学习技术 j,则从 i 向 j 连边,流量为正无穷,最后是工程与技术之间,若工程 i 需要技术 j ,则从 i 想 j 连边,流量为该工程的收益,跑一遍最大流,答案为所有工程的总收益减最大流
ps:不缩点也可以,有环对最大权闭合图的求解没有影响
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#define inf 1000000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=100;
int n,m;
int s,t;
int val[25];
vector<int>need[25];
int cost[55];
int newcost[55];
bool mp[55][55];
struct Tarjan
{
    vector<int>g[55];
    int dfn[55],low[55],sccno[55],dfs_clock,scc_cnt;
    stack<int>s;
    void dfs(int u)
    {
        dfn[u]=low[u]=++dfs_clock;
        s.push(u);
        for(int i=0;i<g[u].size();i++)
        {
            int v=g[u][i];
            if(!dfn[v])
            {
                dfs(v);
                low[u]=min(low[u],low[v]);
            }
            else if(!sccno[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            scc_cnt++;
            while(1)
            {
                int x=s.top();
                s.pop();
                sccno[x]=scc_cnt;
                if(x==u)
                    break;
            }
        }
    }
    void find_scc(int n)
    {
        dfs_clock=scc_cnt=0;
        memset(sccno,0,sizeof(sccno));
        memset(dfn,0,sizeof(dfn));
        while(!s.empty())
            s.pop();
        for(int i=1;i<=n;i++)
            if(!dfn[i])
            dfs(i);
    }
    void init(int n)
    {
        for(int i=1;i<=n;i++)
            g[i].clear();
    }
}suo;
struct Edge
{
    int from,to,cap,flow;
    Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
};
struct Dinic
{
    vector<Edge>edges;
    vector<int>G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int u)
    {
        for(int i=1;i<=u;i++)
            G[i].clear();
        edges.clear();
    }
    void add(int u,int v,int flow)
    {
        edges.push_back(Edge(u,v,flow,0));
        edges.push_back(Edge(v,u,0,0));
        G[u].push_back(edges.size()-2);
        G[v].push_back(edges.size()-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];
    }
    int DFS(int x,int a)
    {
        if(x==t||a==0)
            return a;
        int 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,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;
    }
    int Maxflow(int s,int t)
    {
        int flow=0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            flow+=DFS(s,inf);
        }
        return flow;
    }
}fp;
int main()
{
    int tt;
    scanf("%d",&tt);
    int a;
    int tot;
    int cas=1;
    while(tt--)
    {
        tot=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&val[i]);
            tot+=val[i];
            need[i].clear();
        }
        for(int i=1;i<=m;i++)
            scanf("%d",&cost[i]);
        for(int i=1;i<=n;i++)
        {
            int num;
            scanf("%d",&num);
            for(int j=0;j<num;j++)
            {
                scanf("%d",&a);
                need[i].push_back(a+1);
            }
        }
        suo.init(m);
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf("%d",&mp[i][j]);
                if(mp[i][j]==1)
                    suo.g[i].push_back(j);
            }
        }
        memset(newcost,0,sizeof(newcost));
        suo.find_scc(m);
        for(int i=1;i<=m;i++)
        {
            newcost[suo.sccno[i]]+=cost[i];
        }
        int mm=m;
        m=suo.scc_cnt;
        s=n+m+1,t=n+m+2;
        fp.init(n+m+2);
        for(int i=1;i<=n;i++)
        {
            fp.add(s,i,val[i]);
            vector<int>newneed;
            for(int j=0;j<need[i].size();j++)
                newneed.push_back(suo.sccno[need[i][j]]);
            sort(newneed.begin(),newneed.end());
            int nm=unique(newneed.begin(),newneed.end())-newneed.begin();
            for(int j=0;j<nm;j++)
                fp.add(i,newneed[j]+n,inf);
        }
        for(int i=1;i<=m;i++)
            fp.add(n+i,t,newcost[i]);
        for(int i=1;i<=mm;i++)
        {
            for(int j=1;j<=mm;j++)
            {
                if(mp[i][j]==1)
                {
                    if(suo.sccno[i]!=suo.sccno[j])
                        fp.add(suo.sccno[i]+n,suo.sccno[j]+n,inf);
                }
            }
        }
        printf("Case #%d: %d\n",cas++,tot-fp.Maxflow(s,t));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值