hdu 3879 Base Station【最大权闭包--最大流Dinic】

Base Station

Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65768/32768 K (Java/Others)
Total Submission(s): 2484    Accepted Submission(s): 1068

Problem Description

A famous mobile communication company is planning to build a new set of base stations. According to the previous investigation, n places are chosen as the possible new locations to build those new stations. However, the condition of each position varies much, so the costs to built a station at different places are different. The cost to build a new station at the ith place is Pi (1<=i<=n).

When complete building, two places which both have stations can communicate with each other.

Besides, according to the marketing department, the company has received m requirements. The ith requirement is represented by three integers Ai, Bi and Ci, which means if place Aand Bi can communicate with each other, the company will get Ci profit.

Now, the company wants to maximize the profits, so maybe just part of the possible locations will be chosen to build new stations. The boss wants to know the maximum profits.

Input

Multiple test cases (no more than 20), for each test case:
The first line has two integers n (0<n<=5000) and m (0<m<=50000).
The second line has n integers, P1 through Pn, describes the cost of each location.
Next m line, each line contains three integers, Ai, Bi and Ci, describes the ith requirement.

Output

One integer each case, the maximum profit of the company.

Sample Input

5 5

1 2 3 4 5

1 2 3

2 3 4

1 3 3

1 4 2

4 5 3

Sample Output

4

Author

liulibo

Source

2011 Multi-University Training Contest 5 - Host by BNU

 

题目大意:有n个点,有m条边,对应在一个点上边建一个工厂需要对应Pi的花费,如果某一条边上两个点都建立了工厂,那么就能获得对应的利润。


思路:


关于这个题为什么不会超时...我猜是数据比较水吧,那如果数据不水,这个题要如何优化呢?..........碎碎念


1、点权作为花费,边权作为利润。求一个最大利润的题目,经典的最大权闭包模型问题。


2、建图:

①建立源点S,对应连入各条边(每条边都看成一个点),然后其权值设定为其这条边能够获得的利润。

②建立汇点T,对应将各个点连入汇点,然后其权值设定为这个点建立工厂需要的花费。

③对应将每条边的点连入对应需要建设的两个点,权值为INF。


3、跑一遍最大流Dinic,根据最大流最小割定理 ,这个最大流就是能够获得最大利润条件下的最小建设花费。那么最大实际利润==预期利润-最大流/最小割。


Ac代码:

#include<stdio.h>
#include<queue>
#include<string.h>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
    int from;
    int to;
    int next;
    int w;
}e[5000000];
int divv[5000000];
int cur[500000];
int head[500000];
int n,m,ss,tt,cont;
void add(int from,int to,int w)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
int makedivv()
{
    queue<int >s;
    memset(divv,0,sizeof(divv));
    divv[ss]=1;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        if(u==tt)return 1;
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(w&&divv[v]==0)
            {
                divv[v]=divv[u]+1;
                s.push(v);
            }
        }
    }
    return 0;
}
int Dfs(int u,int maxflow,int tt)
{
    if(u==tt)return maxflow;
    int ret=0;
    for(int &i=cur[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        int w=e[i].w;
        if(w&&divv[v]==divv[u]+1)
        {
            int f=Dfs(v,min(maxflow-ret,w),tt);
            e[i].w-=f;
            e[i^1].w+=f;
            ret+=f;
            if(ret==maxflow)return ret;
        }
    }
    return ret;
}
int Dinic()
{
    int ans=0;
    while(makedivv()==1)
    {
        memcpy(cur,head,sizeof(head));
        ans+=Dfs(ss,INF,tt);
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cont=0;
        memset(head,-1,sizeof(head));
        ss=n+m+1;
        tt=ss+1;
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            int val;
            scanf("%d",&val);
            add(i+m,tt,val);
            add(tt,i+m,0);
        }
        for(int i=1;i<=m;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            sum+=w;
            add(i,x+m,INF);
            add(x+m,i,0);
            add(i,y+m,INF);
            add(y+m,i,0);
            add(ss,i,w);
            add(i,ss,0);
        }
        int ans=Dinic();
        printf("%d\n",sum-ans);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值