标签:prepare name sam 添加 ref cstring dinic time ext
很魔性的一道题。
显然应该根据这个图应该划分成二分图的性质,S点集和T点集分别代表文理科,然后求最小割即可。
如果忽略same_art和same_science的话,建图很显然。所以在这个基础上添加一些东西。
对于每个点,拆为三个点,第一个点正常处理,第二个点和第三个点分别代表same_science和same_art。
以S点集为例。分别连两条边:$S \rightarrow same_{science}$和$same_{science} \rightarrow V_{nxt}$,容量分别为same_science和$\infty$。
为什么这样处理?
首先比如说相邻的五个点都是science,其中有一个要割为art,显然这些点的same_science也要一块割掉,这时候选了art的点还有一条边连着S,即same_art,然后就会被割掉。这样就很好的解决了问题。
//BZOJ 3894 //by Cydiater //2017.1.16 #include <iostream> #include <queue> #include <map> #include <ctime> #include <cstring> #include <string> #include <algorithm> #include <cstdlib> #include <cstdio> #include <iomanip> #include <cmath> #include <bitset> #include <set> #include <vector> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) #define cmax(a,b) a=max(a,b) #define cmin(a,b) a=min(a,b) #define Auto(i,node) for(int i=LINK[node];i;i=e[i].next) const int MAXN=1e3+5; const int oo=0x3f3f3f3f; const int dx[5]={1,0,-1,0,0}; const int dy[5]={0,1,0,-1,0}; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int art[MAXN][MAXN],same_art[MAXN][MAXN],science[MAXN][MAXN],same_science[MAXN][MAXN]; int LINK[MAXN<<10],len=0,N,M,ID[MAXN][MAXN][3],level[MAXN<<10],cnt=0,S,T,ans=0,q[MAXN<<11],head,tail; struct edge{ int y,next,flow,reverse; }e[MAXN<<11]; namespace solution{ inline void insert(int x,int y,int flow,int delta){ e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].flow=flow;e[len].reverse=len+delta; } void Prepare(){ N=read();M=read(); up(i,1,N)up(j,1,M)ans+=(art[i][j]=read()); up(i,1,N)up(j,1,M)ans+=(science[i][j]=read()); up(i,1,N)up(j,1,M)ans+=(same_art[i][j]=read()); up(i,1,N)up(j,1,M)ans+=(same_science[i][j]=read()); up(i,1,N)up(j,1,M)up(k,0,2)ID[i][j][k]=++cnt; S=++cnt;T=++cnt; up(i,1,N)up(j,1,M){ //art insert(S,ID[i][j][0],art[i][j],1); insert(ID[i][j][0],S,0,-1); //science insert(ID[i][j][0],T,science[i][j],1); insert(T,ID[i][j][0],0,-1); //same_art insert(S,ID[i][j][1],same_art[i][j],1); insert(ID[i][j][1],S,0,-1); up(k,0,4){ int tx=i+dx[k],ty=j+dy[k]; if(tx>=1&&tx<=N&&ty>=1&&ty<=M){ insert(ID[i][j][1],ID[tx][ty][0],oo,1); insert(ID[tx][ty][0],ID[i][j][1],0,-1); } } //same_science insert(ID[i][j][2],T,same_science[i][j],1); insert(T,ID[i][j][2],0,-1); up(k,0,4){ int tx=i+dx[k],ty=j+dy[k]; if(tx>=1&&tx<=N&&ty>=1&&ty<=M){ insert(ID[tx][ty][0],ID[i][j][2],oo,1); insert(ID[i][j][2],ID[tx][ty][0],0,-1); } } } } bool makelevel(){ head=1;tail=0;q[++tail]=S; memset(level,-1,sizeof(level)); level[S]=0; for(;head<=tail;head++){ int node=q[head]; Auto(i,node)if(level[e[i].y]==-1&&e[i].flow){ level[e[i].y]=level[node]+1; q[++tail]=e[i].y; } } return level[T]!=-1; } int addflow(int node,int flow){ if(node==T) return flow; int d=0,maxflow=0; Auto(i,node)if(level[e[i].y]==level[node]+1&&e[i].flow) if(d=addflow(e[i].y,min(e[i].flow,flow-maxflow))){ maxflow+=d; e[i].flow-=d; e[e[i].reverse].flow+=d; } if(maxflow<=0)level[node]=-1; return maxflow; } void Dinic(){ int d; while(makelevel()) while(d=addflow(S,oo)) ans-=d; } void Solve(){ Dinic(); printf("%d\n",ans); } } int main(){ //freopen("input.in","r",stdin); using namespace solution; Prepare(); Solve(); return 0; }
标签:prepare name sam 添加 ref cstring dinic time ext
原文地址:http://www.cnblogs.com/Cydiater/p/6290867.html