hdu 4289 最大流拆点

大致题意:
    给出一个又n个点,m条边组成的无向图。给出两个点s,t。对于图中的每个点,去掉这个点都需要一定的花费。求至少多少花费才能使得s和t之间不连通。

大致思路:
    最基础的拆点最大流,把每个点拆作两个点 i 和 i' 连接i->i'费用为去掉这个点的花费,如果原图中有一条边a->b则连接a'->b。对这个图求出最大流即可。

 

画了个图,仔细看看似乎是这么回事

  1 //1002
  2 /*
  3 HDU 4289
  4 G++  62ms  1888K
  5 最大流
  6 SAP
  7 */
  8 #include<stdio.h>
  9 #include<iostream>
 10 #include<map>
 11 #include<set>
 12 #include<algorithm>
 13 #include<string.h>
 14 #include<stdlib.h>
 15 using namespace std;
 16 
 17 const int MAXN=5000;//点数的最大值
 18 const int MAXM=2500000;//边数的最大值
 19 const int INF=0x3f3f3f3f;
 20 
 21 struct Node
 22 {
 23     int from,to,next;
 24     int cap;
 25 }edge[MAXM];
 26 int tol;
 27 int head[MAXN];
 28 int dep[MAXN];
 29 int gap[MAXN];//gap[x]=y:说明残留网络中 dep[i]==x的个数为y
 30 
 31 int n;//点的实际个数,一定是总的点的个数,包括源点和汇点
 32 void init()
 33 {
 34     tol=0;
 35     memset(head,-1,sizeof(head));
 36 }
 37 void addedge(int u,int v,int w)
 38 {
 39     edge[tol].from=u;
 40     edge[tol].to=v;
 41     edge[tol].cap=w;
 42     edge[tol].next=head[u];
 43     head[u]=tol++;
 44     edge[tol].from=v;
 45     edge[tol].to=u;
 46     edge[tol].cap=0;
 47     edge[tol].next=head[v];
 48     head[v]=tol++;
 49 }
 50 void BFS(int start,int end)
 51 {
 52     memset(dep,-1,sizeof(dep));
 53     memset(gap,0,sizeof(gap));
 54     gap[0]=1;
 55     int que[MAXN];
 56     int front,rear;
 57     front=rear=0;
 58     dep[end]=0;
 59     que[rear++]=end;
 60     while(front!=rear)
 61     {
 62         int u=que[front++];
 63         if(front==MAXN)front=0;
 64         for(int i=head[u];i!=-1;i=edge[i].next)
 65         {
 66             int v=edge[i].to;
 67             if(edge[i].cap!=0||dep[v]!=-1)continue;
 68             que[rear++]=v;
 69             if(rear==MAXN)rear=0;
 70             dep[v]=dep[u]+1;
 71             ++gap[dep[v]];
 72         }
 73     }
 74 }
 75 int SAP(int start,int end)
 76 {
 77     int res=0;
 78     BFS(start,end);
 79     int cur[MAXN];
 80     int S[MAXN];
 81     int top=0;
 82     memcpy(cur,head,sizeof(head));
 83     int u=start;
 84     int i;
 85     while(dep[start]<n)
 86     {
 87         if(u==end)
 88         {
 89             int temp=INF;
 90             int inser;
 91             for(i=0;i<top;i++)
 92                if(temp>edge[S[i]].cap)
 93                {
 94                    temp=edge[S[i]].cap;
 95                    inser=i;
 96                }
 97             for(i=0;i<top;i++)
 98             {
 99                 edge[S[i]].cap-=temp;
100                 edge[S[i]^1].cap+=temp;
101             }
102             res+=temp;
103             top=inser;
104             u=edge[S[top]].from;
105         }
106         if(u!=end&&gap[dep[u]-1]==0)//出现断层,无增广路
107           break;
108         for(i=cur[u];i!=-1;i=edge[i].next)
109            if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)
110              break;
111         if(i!=-1)
112         {
113             cur[u]=i;
114             S[top++]=i;
115             u=edge[i].to;
116         }
117         else
118         {
119             int min=n;
120             for(i=head[u];i!=-1;i=edge[i].next)
121             {
122                 if(edge[i].cap==0)continue;
123                 if(min>dep[edge[i].to])
124                 {
125                     min=dep[edge[i].to];
126                     cur[u]=i;
127                 }
128             }
129             --gap[dep[u]];
130             dep[u]=min+1;
131             ++gap[dep[u]];
132             if(u!=start)
133               u=edge[S[--top]].from;
134         }
135 
136     }
137     return res;
138 }
139 
140 int main()
141 {
142     //freopen("B.in","r",stdin);
143     //freopen("B.out","w",stdout);
144     int N,M;
145     int u,v;
146     int start;
147     int end;
148     while(scanf("%d%d",&N,&M)!=EOF)
149     {
150         init();
151         scanf("%d%d",&start,&end);
152         start=2*start-1;
153         end=2*end;
154         n=2*N;
155         for(int i=1;i<=N;i++)
156         {
157             scanf("%d",&u);
158             addedge(2*i-1,2*i,u);
159             addedge(2*i,2*i-1,u);
160         }
161         while(M--)
162         {
163             scanf("%d%d",&u,&v);
164             addedge(2*u,2*v-1,INF);
165             addedge(2*v,2*u-1,INF);//这里一定要注意
166         }
167         printf("%d\n",SAP(start,end));
168     }
169     return 0;
170 }

 

转载于:https://www.cnblogs.com/cnblogs321114287/p/4356821.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值