HDU 3879 最大树闭合图

来源:互联网 发布:自学编程语言 知乎 编辑:程序博客网 时间:2024/05/22 08:16
思路:参照论文:

《最小割模型在信息学竞赛中的应用》(胡伯涛著)

PPT链接:http://wenku.baidu.com/view/6507a6fe2cc58bd63186bdaf.html

里面建图和理解都比较清楚了。

把边变成点,然后建二部图,源点向点连边,容量为p[i];点向边连边,容量为INF;边向汇点连边,容易为w[i];然后求最小割,即图中不用的点和边之和,也即最大流,然后总的收益减去这个最小割即是所求。

#pragma comment(linker, "/STACK:1024000000,1024000000")//#include<bits/stdc++.h>#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<map>#include<queue>#include<set>#include<cmath>#include<bitset>#define mem(a,b) memset(a,b,sizeof(a))#define lson i<<1,l,mid#define rson i<<1|1,mid+1,r#define llson j<<1,l,mid#define rrson j<<1|1,mid+1,rtypedef long long ll;typedef unsigned long long ull;using namespace std;#define INF 0x7fffffff#define maxn 100005int n,cnt,d[maxn],head[maxn],q[maxn*10];int sink;//sink为汇点,0为源点struct node{    int v,w,next;}e[maxn*10];void add(int u,int v,int w){    e[cnt].v=v; e[cnt].w=w;    e[cnt].next=head[u]; head[u]=cnt++;    e[cnt].v=u; e[cnt].w=0;    e[cnt].next=head[v]; head[v]=cnt++;}int bfs(){    mem(d,-1);    int l=0,r=0;    q[r++]=0; d[0]=0;    while(l<r)  //找增广路    {        int u=q[l++];        for(int i=head[u];i!=-1;i=e[i].next)        {            if(d[e[i].v]==-1&&e[i].w)            {                d[e[i].v]=d[u]+1;                if(e[i].v!=sink) q[r++]=e[i].v;            }        }    }    return d[sink]!=-1;}int dfs(int u,int Min){    int sum,duolu=0;    if(u==sink) return Min;    for(int i=head[u];i!=-1&&Min-duolu>0;i=e[i].next)        if(e[i].w&&d[e[i].v]==d[u]+1&&(sum=dfs(e[i].v,min(Min-duolu,e[i].w))))        {            e[i].w-=sum;            e[i^1].w+=sum;            duolu+=sum;            if(duolu==Min) break;        }    return duolu;}int Dinic(){    int tmp,ans=0;    while(bfs())    {        while(tmp=dfs(0,INF)) ans+=tmp;    }    return ans;}void init(){    mem(head,-1), cnt=0;}int main(){    //freopen("1.txt","r",stdin);    int m;    while(~scanf("%d%d",&n,&m))    {        int w,sum=0,u,v;        init();        sink=n+m+1;        for(int i=1;i<=n;i++)        {            scanf("%d",&w);            add(i+m,sink,w);        }        for(int i=1;i<=m;i++)        {            scanf("%d%d%d",&u,&v,&w);            add(i,u+m,INF);            add(i,v+m,INF);            add(0,i,w);            sum+=w;        }        printf("%d\n",sum-Dinic());    }    return 0;}


0 0