bzoj1497: [NOI2006]最大获利 最大权闭合子图

新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战。THU集团旗下的CS&T通讯公司在新一代通讯技术血战的前夜,需要做太多的准备工作,仅就站址选择一项,就需要完成前期市场研究、站址勘测、最优化等项目。在前期市场调查和站址勘测之后,公司得到了一共N个可以作为通讯信号中转站的地址,而由于这些地址的地理位置差异,在不同的地方建造通讯中转站需要投入的成本也是不一样的,所幸在前期调查之后这些都是已知数据:建立第i个通讯中转站需要的成本为Pi(1≤i≤N)。另外公司调查得出了所有期望中的用户群,一共M个。关于第i个用户群的信息概括为Ai, Bi和Ci:这些用户会使用中转站Ai和中转站Bi进行通讯,公司可以获益Ci。(1≤i≤M, 1≤Ai, Bi≤N) THU集团的CS&T公司可以有选择的建立一些中转站(投入成本),为一些用户提供服务并获得收益(获益之和)。那么如何选择最终建立的中转站才能让公司的净获利最大呢?(净获利 = 获益之和 - 投入成本之和)
题解:最大权闭合子图,对于一个有向图来说,每个节点有权值(可正可负),求找一张子图满足点权和最大,对于一条边u->v来说,如果u被选中了,那么v也要被选中,可以转化成最小割模型,点权和最大即正点权-最小割,最小割是s想正点权点连一条容量为点权的边,负点权点连一条容量为负点权的边,原图中的边容量为inf,那么对于这题来说只需要把边也看成点,跑一遍最小割即可

/**************************************************************
    Problem: 1497
    User: walfy
    Language: C++
    Result: Accepted
    Time:2172 ms
    Memory:25288 kb
****************************************************************/
 
//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
#define mod 1000000007
#define ld long double
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)
 
using namespace std;
 
const double eps=1e-6;
const int N=55000+10,maxn=2000000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;
 
struct edge{
    int to,Next,c;
}e[maxn];
int s,t,cnt,head[N];
void init()
{
    cnt=0;
    memset(head,-1,sizeof head);
}
void add(int u,int v,int c)
{
    e[cnt].to=v;
    e[cnt].c=c;
    e[cnt].Next=head[u];
    head[u]=cnt++;
    e[cnt].to=u;
    e[cnt].c=0;
    e[cnt].Next=head[v];
    head[v]=cnt++;
}
int dis[N];
bool bfs()
{
    queue<int>q;
    memset(dis,-1,sizeof dis);
    dis[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();q.pop();
        for(int i=head[x];~i;i=e[i].Next)
        {
            int y=e[i].to;
            if(dis[y]==-1&&e[i].c>0)
            {
                dis[y]=dis[x]+1;
                q.push(y);
            }
        }
    }
    return dis[t]!=-1;
}
int dfs(int u,int mx)
{
    if(u==t)return mx;
    int flow=0,f;
    for(int i=head[u];~i;i=e[i].Next)
    {
        int x=e[i].to;
        if(dis[x]==dis[u]+1&&e[i].c>0&&(f=dfs(x,min(mx-flow,e[i].c))))
        {
            e[i].c-=f;
            e[i^1].c+=f;
            flow+=f;
        }
    }
    if(flow==0)dis[u]=-2;
    return flow;
}
int maxflow()
{
    int ans=0,f;
    while(bfs())
    {
        while((f=dfs(s,inf)))ans+=f;
    }
    return ans;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    s=n+m+1,t=n+m+2;
    init();
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int c;
        scanf("%d",&c);
        add(i,t,c);
    }
    for(int i=1;i<=m;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);ans+=c;
        add(i+n,a,inf);
        add(i+n,b,inf);
        add(s,i+n,c);
    }
    printf("%d
",ans-maxflow());
    return 0;
}
/********************
 
********************/
原文地址:https://www.cnblogs.com/acjiumeng/p/9130175.html