HDU 3879 最大密度子图

来源:互联网 发布:淘宝演唱会有假票吗 编辑:程序博客网 时间:2024/05/13 02:47

思路:

见论文:

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

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

里面有这题的建边和解决方法了。

源点到点连边,容量为U(无限大);然后点与点之间连无向边,容量为p[i];然后点与汇点连边,容量为:U+2*p[i]-du[i]。这是根据论文中的建边方式建的。

这题不像POJ 3155那题一样是01规划,需要01规划二分去找最值,这题只要跑一遍最大流就得到最佳答案了,答案在论文中就是:(U*n-C(s,t))/2(C(s,t)即网络中的最小割),即(U*n-Dinic())/2。

搞下Dinic多路增广求最大流就不会T了。

#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 5005int n,cnt,d[maxn],head[maxn],du[maxn],q[maxn*100];int sink;//sink为汇点,0为源点struct node{    int v,w,next;}e[maxn*50];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 p[maxn];int main(){    //freopen("1.txt","r",stdin);    int m;    while(~scanf("%d%d",&n,&m))    {        int U=1000000,u,v,w;        init();mem(du,0);sink=n+1;        for(int i=1;i<=n;i++)        {            scanf("%d",p+i);            add(0,i,U);        }        for(int i=1;i<=m;i++)        {            scanf("%d%d%d",&u,&v,&w);            add(u,v,w),add(v,u,w);            du[u]+=w,du[v]+=w;        }        for(int i=1;i<=n;i++)            add(i,sink,U+2*p[i]-du[i]);        printf("%d\n",(U*n-Dinic())/2);    }    return 0;}


0 0