1. 程式人生 > >「網絡流24題」 9. 方格取數問題

「網絡流24題」 9. 方格取數問題

tps const str pro inf 網絡流 edge ++ ans

「網絡流24題」 9. 方格取數問題

<題目鏈接>


二分圖的最大點權獨立集

建立二分圖,使得每個點與其相鄰的點在不同的部。

源向X部引有向邊,Y部向匯引有向邊,邊權為點權。

X部每個點到其相鄰的點引有向邊,邊權INF,這個邊的兩個斷電不能同時被選。

那麽S-X-Y-T的任意一條增廣路都表示選了兩個相鄰的點。

於是問題轉化為求網絡最小割。

最終的答案為所有點的點權和(先都選上)減去網絡最小割(不能選的最小點權集)。

#include <algorithm>
#include <climits>
#include <cstdio>
#include <cstring>
#include <queue> using namespace std; const int MAXN=10010,MAXM=59610; int m,n,S,T,cnt,ans,head[MAXN],cur[MAXN],dis[MAXN]; struct edge { int nxt,to,w; }e[MAXM]; void AddEdge(int x,int y,int w) { e[++cnt].nxt=head[x]; e[cnt].to=y; e[cnt].w=w; head[x]=cnt; } void AddEdges(int x,int
y,int w) { AddEdge(x,y,w); AddEdge(y,x,0); } int num(int i,int j) { return (i-1)*n+j; } void Init(int i,int j) { int w,t=num(i,j); scanf("%d",&w); ans+=w; if(i+j&1) AddEdges(t,T,w); else { AddEdges(S,t,w); if(i>1) AddEdges(t,t-n,INT_MAX); if
(i<m) AddEdges(t,t+n,INT_MAX); if(j>1) AddEdges(t,t-1,INT_MAX); if(j<n) AddEdges(t,t+1,INT_MAX); } } bool BFS(void) { queue<int> q; memset(dis,0,sizeof dis); q.push(S); dis[S]=1; while(!q.empty()) { int x=q.front(); q.pop(); for(int i=head[x],t;i;i=e[i].nxt) if(e[i].w && !dis[t=e[i].to]) { q.push(t); dis[t]=dis[x]+1; } } return dis[T]; } int DFS(int x,int k) { if(x==T || !k) return k; int tmp=0; for(int i=cur[x],t,flow;i;i=e[i].nxt) if(e[i].w && dis[t=e[i].to]==dis[x]+1 && (flow=DFS(t,min(k,e[i].w)))) { cur[x]=i; e[i].w-=flow; e[((i-1)^1)+1].w+=flow; k-=flow; tmp+=flow; } if(!tmp) dis[x]=0; return tmp; } void Dinic(void) { int flow; while(BFS()) while(memcpy(cur,head,sizeof cur),flow=DFS(S,INT_MAX)) ans-=flow; } int main(int argc,char *argv[]) { scanf("%d %d",&m,&n); T=m*n+1; for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) Init(i,j); Dinic(); printf("%d",ans); return 0; }

謝謝閱讀

「網絡流24題」 9. 方格取數問題