1. 程式人生 > >[GDKOI2010] 圈地計劃(網絡流)

[GDKOI2010] 圈地計劃(網絡流)

pre 數組 類型 inf tar 不同 了解 oid return

題2鏈接:https://www.luogu.org/problemnew/show/P1935

Description

最近房地產商GDOI(Group of Dumbbells Or Idiots)從NOI(Nuts Old Idiots)手中得到了一塊開發土地。據了解,這塊土地是一塊矩形的區域,可以縱橫劃分為N×M塊小區域。GDOI要求將這些區域分為商業區和工業區來開發。根據不同的地形環境,每塊小區域建造商業區和工業區能取得不同的經濟價值。更具體點,對於第i行第j列的區域,建造商業區將得到Aij收益,建造工業區將得到Bij收益。

題1
另外同種的區域連在一起可以得到額外的收益,即如果相鄰有K塊(顯然K不超過4)同種類型的區域,則這塊區域能增加k×Cij收益。

上面註意是相同的區域可獲得收益,而下面的是不同的區域可獲得收益

題2
另外不同的區域連在一起可以得到額外的收益,即如果區域(I,j)相鄰(相鄰是指兩個格子有公共邊)有K塊(顯然K不超過4)類型不同於(I,j)的區域,則這塊區域能增加k×Cij收益。

經過Tiger.S教授的勘察,收益矩陣A,B,C都已經知道了。你能幫GDOI求出一個收益最大的方案麽?

我們首先看T1

仔細看題,對於每一塊區域我們要選擇它是商業區還是工業區。嗯?分成兩個?在考慮若是所有的c數組不論該點選怎麽都能顫聲貢獻,我們最後減去最小的多算的貢獻就好了。

註意這所謂最小的貢獻必須建立在每一塊區域都被明確的選擇了類型上

於是乎,很容易就可以想到求最小的貢獻就是直接最小割了

那麽如何建圖?

(相同的有額外收益) 則源點向所有點連商業區的收益,所有點向匯點連工業區的收益,相鄰的點連雙向邊額外的收益

答案就是總收益減去最小割

T1就是這樣

#include<bits/stdc++.h>
using namespace std;

const int inf=1e9+7;
const int maxn=100+15;
int n,m,tot=-1,s,t;
int head[maxn*maxn],c[maxn][maxn],chead[maxn*maxn],vis[maxn*maxn];
int l[4]={1,0},r[4]={0,1}; struct EDGE { int to,next,cap; }edge[maxn<<15]; inline int read() { char ch=getchar(); int s=0,f=1; while (!(ch>=0&&ch<=9)) {if (ch==-) f=-1;ch=getchar();} while (ch>=0&&ch<=9) {s=(s<<3)+(s<<1)+ch-0;ch=getchar();} return s*f; } int get(int x,int y) { return (x-1)*m+y; } void add(int x,int y,int z1,int z2) { edge[++tot]=(EDGE){y,head[x],z1}; head[x]=tot; edge[++tot]=(EDGE){x,head[y],z2}; head[y]=tot; } bool bfs() { memset(vis,0,sizeof(vis)); queue <int> q; vis[s]=1; q.push(s); while (!q.empty()) { int k=q.front();q.pop(); for (int i=head[k];i!=-1;i=edge[i].next) { int y=edge[i].to; if (!vis[y]&&edge[i].cap) { vis[y]=vis[k]+1; q.push(y); } } } return vis[t]!=0; } int dfs(int x,int flow) { if (x==t||!flow) return flow; int f,a=0; for (int &i=chead[x];i!=-1;i=edge[i].next) { int y=edge[i].to; if (vis[y]==vis[x]+1&&(f=dfs(y,min(edge[i].cap,flow)))>0) { edge[i].cap-=f; edge[i^1].cap+=f; a+=f; flow-=f; if (flow==0) break; } } if (a==0) vis[x]=-1; return a; } int dinic() { int ans=0; while (bfs()) { for (int i=0;i<=n*m+1;i++) chead[i]=head[i]; ans+=dfs(s,inf); } return ans; } int main() { int ans=0; n=read();m=read(); s=0;t=n*m+1; memset(head,-1,sizeof(head)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int x=read(); add(s,get(i,j),x,0); ans+=x; } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { int x=read(); add(get(i,j),t,x,0); ans+=x; } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) c[i][j]=read(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) for (int k=0;k<=1;k++) { int x1=i+l[k],y1=j+r[k]; if (x1<=0||x1>n||y1<=0||y1>m) continue; add(get(i,j),get(x1,y1),c[i][j]+c[x1][y1],c[i][j]+c[x1][y1]); ans+=(c[i][j]+c[x1][y1]); } printf("%d",ans-dinic()); return 0; }

[GDKOI2010] 圈地計劃(網絡流)