hdu4289 Control (ISAP算法)

来源:互联网 发布:淘宝我的回答能删除么 编辑:程序博客网 时间:2024/06/05 14:08

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4289


题解:将点权转化为边权,拆点,(i,i+n)之间连边,容量为在城市i的花费,然后就是若u,v之间有路,则连边(u+n,v),(v+n,u).最后就是跑最大流了。

常用的两种拆点方式:

    1. 对于每个节点id,拆成 id<<1 和 id<<1|1 两个点

    2.对于每个节点id,拆成 id 和 id+n 两个点


#include <cstdio>#include <cstring>#define INF 0x3f3f3f3f#define MAXN 402#define MAXE 100002using namespace std;struct node{int from,to,next;int cap;}edge[MAXE];int N,src,sink,tot,pre[MAXN],cur[MAXN];int head[MAXN],level[MAXN],gap[MAXN],Queue[MAXN];void addEdge(int u,int v,int w){edge[tot].to=v;edge[tot].cap=w;edge[tot].next=head[u];head[u]=tot++;edge[tot].to=u;edge[tot].cap=0;edge[tot].next=head[v];head[v]=tot++;}void BFS(int dest){int u,v,i,front,rear;memset(level,-1,sizeof(level));memset(gap,0,sizeof(gap));level[dest]=0;++gap[0];front=rear=0;Queue[rear++]=dest;while(front<rear){u=Queue[front++];for(i=head[u];i!=-1;i=edge[i].next){v=edge[i].to;if(level[v]!=-1)continue;level[v]=level[u]+1;++gap[level[v]];Queue[rear++]=v;}}}int ISAP(int dest){int u,v,flag,aug,minlevel,maxflow=0;BFS(dest);memset(pre,-1,sizeof(pre));memcpy(cur,head,sizeof(head));aug=INF;u=pre[src]=src;gap[0]=N;while(level[src]<N){flag=0;for(int &i=cur[u];i!=-1;i=edge[i].next){v=edge[i].to;if(edge[i].cap>0&&level[u]==level[v]+1){flag=1;pre[v]=u;u=v;aug=aug<edge[i].cap?aug:edge[i].cap;if(v==dest){maxflow+=aug;for(u=pre[v];v!=src;v=u,u=pre[u]){edge[cur[u]].cap-=aug;edge[cur[u]^1].cap+=aug;}aug=INF;}break;}}if(flag)continue;minlevel=N;for(int i=head[u];i!=-1;i=edge[i].next){v=edge[i].to;if(edge[i].cap>0&&level[v]<minlevel){cur[u]=i;minlevel=level[v];}}if(--gap[level[u]]==0)break;level[u]=minlevel+1;++gap[level[u]];u=pre[u];}return maxflow;}int main(){int u,v,w,n,m,i,ans;while(scanf("%d %d",&n,&m)!=EOF){N=n*2;tot=0;memset(head,-1,sizeof(head));scanf("%d %d",&src,&sink);for(i=1;i<=n;++i){scanf("%d",&w);addEdge(i,i+n,w);}while(m--){scanf("%d %d",&u,&v);addEdge(u+n,v,INF);addEdge(v+n,u,INF);}ans=ISAP(sink+n);printf("%d\n",ans);}return 0;}


 


原创粉丝点击