★ HDU 3917 最大权闭合图模型

来源:互联网 发布:斗鱼 炒股 知乎 编辑:程序博客网 时间:2024/06/05 02:32

题意:n个城市,m个公司修路,如果选择了A公司,则A公司负责的所有路都要修,另外,和A公司有关系的B公司也要选择,(如果A修了(1,2),B修了(2,3),则称A和B有关系,关系有方向),此题为最大权闭合图模型,另外,将税收和代价可以合并为一个点,因为选择了该点的税收,则代价也必须选,这样可以减少点的个数。

代码:

//Isap算法,复杂度O(n^2m)#pragma comment(linker,"/STACK:102400000,102400000")#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#include <vector>#include <string>#include <math.h>#include <queue>#include <stack>#include <map>#include <set>using namespace std;typedef long long ll;   //记得必要的时候改成无符号const int maxn=5005;const int maxm=1000005;const int INF=1000000000;struct EdgeNode{    int from;    int to;    int cost;    int next;}edge[maxm];int head[maxn],cnt;void add(int x,int y,int z){    edge[cnt].from=x;edge[cnt].to=y;edge[cnt].cost=z;edge[cnt].next=head[x];head[x]=cnt++;    edge[cnt].from=y;edge[cnt].to=x;edge[cnt].cost=0;edge[cnt].next=head[y];head[y]=cnt++;    //printf("%d %d %d\n",x,y,z);}void init(){    cnt=0;    memset(head,-1,sizeof(head));}int S,T,n,m;int d[maxn],gap[maxn],curedge[maxn],pre[maxn];//curedge[]为当前弧数组,pre为前驱数组int sap(int S,int T,int n)  //n为点数{    int cur_flow,flow_ans=0,u,tmp,neck,i;    memset(d,0,sizeof(d));    memset(gap,0,sizeof(gap));    memset(pre,-1,sizeof(pre));    for(i=0;i<=n;i++)curedge[i]=head[i]; //初始化当前弧为第一条邻接表    gap[0]=n;    u=S;    while(d[S]<n)             //当d[S]>=n时,网络中肯定出现了断层    {        if(u==T)        {            cur_flow=INF;            for(i=S;i!=T;i=edge[curedge[i]].to)            {                           //增广成功,寻找瓶颈边                if(cur_flow>edge[curedge[i]].cost)                {                    neck=i;                    cur_flow=edge[curedge[i]].cost;                }            }            for(i=S;i!=T;i=edge[curedge[i]].to)            {                             //修改路径上的边容量                tmp=curedge[i];                edge[tmp].cost-=cur_flow;                edge[tmp^1].cost+=cur_flow;            }            flow_ans+=cur_flow;            u=neck;                     //下次增广从瓶颈边开始        }        for(i=curedge[u];i!=-1;i=edge[i].next)            if(edge[i].cost&&d[u]==d[edge[i].to]+1)               break;        if(i!=-1)        {            curedge[u]=i;            pre[edge[i].to]=u;            u=edge[i].to;        }        else        {            if(0==--gap[d[u]])break;    //gap优化            curedge[u]=head[u];            for(tmp=n,i=head[u];i!=-1;i=edge[i].next)                if(edge[i].cost)                   tmp=min(tmp,d[edge[i].to]);            d[u]=tmp+1;            ++gap[d[u]];            if(u!=S)u=pre[u];           //重标号并且从当前点前驱重新增广        }    }    return flow_ans;}int zhi[maxn];struct q{    int v,bj;    q(){};    q(int v,int bj):v(v),bj(bj){}};vector<q>V[maxn];int main(){    int ans,i,x,y,c,w,k,j;    while(~scanf("%d%d",&n,&m)&&(n+m))    {        ans=0;        for(i=1;i<=n;i++)V[i].clear();        memset(zhi,0,sizeof(zhi));        init(); S=0; T=m+1;        for(i=1;i<=m;i++){            scanf("%d",&x);            add(S,i,x);            ans+=x;        }        scanf("%d",&k);        for(i=1;i<=k;i++){            scanf("%d%d%d%d",&x,&y,&c,&w);            V[x].push_back(q(y,c));            zhi[c]+=w;        }        for(i=1;i<=m;i++)add(i,T,zhi[i]);        for(i=1;i<=n;i++){            for(j=0;j<V[i].size();j++){                for(k=0;k<V[V[i][j].v].size();k++){                    if(V[i][j].bj!=V[V[i][j].v][k].bj)                        add(V[i][j].bj,V[V[i][j].v][k].bj,INF);                }            }        }        n=T+1;        printf("%d\n",ans-sap(S,T,n));    }}


0 0