码迷,mamicode.com
首页 > 编程语言 > 详细

hiho一下 第119周 #1398 : 网络流五·最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

时间:2017-02-28 19:51:18      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:最大的   oid   sans   term   _id   code   hit   矛盾   header   

#1398 : 网络流五·最大权闭合子图

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

周末,小Hi和小Ho所在的班级决定举行一些班级建设活动。

根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值。

班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值。

每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行。

班级建设的活跃值是活动产生的总活跃值减去邀请学生所花费的活跃值。

小Hi和小Ho需要选择进行哪些活动,来保证班级建设的活跃值尽可能大。

 
 

比如有3项活动,4名学生:

第1项活动产生5的活跃值,需要编号为1、2的学生才能进行;

第2项活动产生10的活跃值,需要编号为3、4的学生才能进行;

第3项活动产生8的活跃值,需要编号为2、3、4的学生才能进行。

编号为1到4的学生需要消耗的活跃值分别为6、3、5、4。

假设举办活动集合为{1},需要邀请的学生集合为{1,2},则得到的班级活跃值为5-9 = -4。

假设举办活动集合为{2},需要邀请的学生集合为{3,4},则得到的班级活跃值为10-9 = 1。

假设举办活动集合为{2,3},需要邀请的学生集合为{2,3,4},则得到的班级活跃值为18-12 = 6。

假设举办活动集合为{1,2,3},需要邀请的学生集合为{1,2,3,4},则得到的班级活跃值为23-18 = 5。

小Hi和小Ho总是希望班级活跃值越大越好,因此在这个例子中,他们会选择举行活动2和活动3。

输入

第1行:两个正整数N,M。1≤N≤200,1≤M≤200

第2行:M个正整数,第i个数表示邀请编号为i的学生需要花费的活跃值b[i],1≤b[i]≤1,000

第3..N+2行:第i行表示编号为i的活动情况。首先是2个整数a,k,a表示该活动产生的活跃值,k表示该活动需要的学生人数。接下来k个整数列举该活动需要的学生编号。1≤a≤1,000,1≤k≤M

输出

第1行:1个整数,最大可以产生的班级活跃值

样例输入
3 4
6 3 5 4
5 2 1 2
10 2 3 4
8 3 2 3 4
样例输出
6

最大权闭合子图的权值等于所有正权点之和减去最小割。

这次求最大流时犯了一个错误呀-.-  递归中竟然用了一个外部变量来转换--- 递归后量就变了---坑了自己一下午


Dinic 算法 :每次求可行流量时先bfs一下,然后dfs时对于边 ( w - u) 只考虑 u 的深度大于 w 的边就行dfs 。比Ford-Fulkerson快了好多---

技术分享


Ford-Fulkerson代码:

#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
    int to,cap,fac;
}Q;
vector<node> V[4200];
bool fafe[4200];
void add_edge(int a,int b,int c)
{
    Q.to=b;Q.cap=c;Q.fac=V[b].size();
    V[a].push_back(Q);
    Q.to=a;Q.cap=0;Q.fac=V[a].size()-1;
    V[b].push_back(Q);
}
int mi_graph(int s,int t,int ans)
{
    if (s==t) return ans;
    fafe[s]=true;
    int v;
    for (int i=0;i<V[s].size();i++)
    {
        if (fafe[V[s][i].to]||V[s][i].cap==0) continue;
        v=mi_graph(V[s][i].to,t,min(ans,V[s][i].cap));
        if (v)
        {
            V[s][i].cap-=v;
            V[V[s][i].to][V[s][i].fac].cap+=v;
            return v;
        }
    }
    return 0;
}
int main()
{
    int n,m,s,t,a,b,MIX=0x3f3f3f3f,ans;
    while (~scanf("%d%d",&n,&m))
    {
        s=0;t=n+m+1;ans=0;
        for (int i=0;i<=t;i++)
            V[i].clear();
        for (int i=1;i<=m;i++)
        {
            cin>>a;
            add_edge(i+n,t,a);
        }
        for (int i=1;i<=n;i++)
        {
            cin>>a;
            ans+=a;
            add_edge(s,i,a);
            cin>>b;
            while (b--)
            {
                cin>>a;
                add_edge(i,a+n,MIX);
            }
        }
        int k=1;
        while (k)
        {
            memset(fafe,false,sizeof(fafe));
            k=mi_graph(s,t,MIX);
            ans-=k;
        }
        cout<<ans<<endl;
    }
    return 0;
}



Dinic代码:

#include<cstdio>
#include<vector>
#include<queue>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
struct node{
    int to,cap,fac;
}Q;
vector<node> V[420];
bool fafe[420];
int level[420];
void add_edge(int a,int b,int c)
{
    Q.to=b;Q.cap=c;Q.fac=V[b].size();
    V[a].push_back(Q);
    Q.to=a;Q.cap=0;Q.fac=V[a].size()-1;
    V[b].push_back(Q);
}
int dfs(int s,int t,int MIX)
{
    if (s==t) return MIX;
    for (int i=0;i<V[s].size();i++)
    {
        /*Q=V[s][i];
        if (level[Q.to]>level[s]&&Q.cap!=0)
        {
            int ls=dfs(Q.to,t,min(MIX,Q.cap));
            if (ls)
            {
                V[s][i].cap-=ls;
                V[Q.to][Q.fac].cap+=ls;
                return ls;
            }
        }*/
        if (level[V[s][i].to]>level[s]&&V[s][i].cap!=0)
        {
            int ls=dfs(V[s][i].to,t,min(MIX,V[s][i].cap));
            if (ls)
            {
                V[s][i].cap-=ls;
                V[V[s][i].to][V[s][i].fac].cap+=ls;
                return ls;
            }
        }
    }
    return 0;
}
int mi_graph(int s,int t,int MIX)
{
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s]=0;
    int v;
    que.push(s);
    while (!que.empty())
    {
        v=que.front();
        que.pop();
        for (int i=0;i<V[v].size();i++)
        {
            Q=V[v][i];
            if (level[Q.to]!=-1||Q.cap==0) continue;
            que.push(Q.to);
            level[Q.to]=level[v]+1;
        }
    }
    if (level[t]==-1)
        return 0;
    int ans=1,sum=0;
    while (ans)
    {
        ans=dfs(s,t,MIX);
        sum+=ans;
    }
    return sum;
}
int main()
{
    int n,m,s,t,a,b,ans,ss,MIX;
    MIX=INF;
    scanf("%d%d",&n,&m);
    s=0;t=n+m+1;ans=0;
    for (int i=0;i<=t;i++)
        V[i].clear();
    for (int i=1;i<=m;i++)
    {
        cin>>a;
        add_edge(i+n,t,a);
    }
    for (int i=1;i<=n;i++)
    {
        cin>>a;
        ans+=a;
        add_edge(s,i,a);
        cin>>b;
        while (b--)
        {
            cin>>a;
            add_edge(i,a+n,MIX);
        }
    }
    int k=1;ss=0;
    while (k)
    {
        k=mi_graph(s,t,MIX);
        ss+=k;
    }
    cout<<ans-ss<<endl;
    return 0;
}










hiho一下 第119周 #1398 : 网络流五·最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

标签:最大的   oid   sans   term   _id   code   hit   矛盾   header   

原文地址:http://blog.csdn.net/leibniz_zhang/article/details/58606543

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!