首页 > 代码库 > BZOJ3894: 文理分科
BZOJ3894: 文理分科
传送门
很魔性的一道题。
显然应该根据这个图应该划分成二分图的性质,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;}
BZOJ3894: 文理分科
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。