P4313-文理分科【最小割】
正題
題目鏈接:https://www.luogu.com.cn/problem/P4313
題目大意
有n?mn*mn?m個人,第(i,j)(i,j)(i,j)選擇文科就可以獲得arti,jart_{i,j}arti,j?的價值,選擇理科就可以獲得scii,jsci_{i,j}scii,j?的價值。如果一個選擇文科的人周圍都選擇了文科,那么就可以多獲得same_arti,jsame\_art_{i,j}same_arti,j?的價值。如果一個選擇了理科的人周圍都選擇了理科,那么就可以多獲得same_scii,jsame\_sci_{i,j}same_scii,j?的價值。
求最大價值和。
解題思路
顯然不考慮samesamesame的話如何將其模型轉移到網絡流上,考慮最小割。我們對于每個同學(i,j)(i,j)(i,j)建立一個節點pi,j,0p_{i,j,0}pi,j,0?,然后S?>pi,j,0S->p_{i,j,0}S?>pi,j,0?流量為arti,jart_{i,j}arti,j?,pi,j,0?>Tp_{i,j,0}->Tpi,j,0??>T流量為scii,jsci_{i,j}scii,j?。
考慮如何加入samesamesame入這個模型中,先考慮文科的,對于一個點我們發現如果它周圍的都割掉了理科的邊就不需要割same_artsame\_artsame_art,也就是我們需要新建一個節點連接這些周圍的節點,這樣這些被連接的節點就必須要割掉連向TTT的邊 。顯然我們還需要建立S?>pi,j,1S->p_{i,j,1}S?>pi,j,1?流量為same_arti,jsame\_art_{i,j}same_arti,j?
same_scii,jsame\_ sci_{i,j}same_scii,j?同理。
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define p(x,y,z) ((((x)-1)*m+(y))+(z)*S) using namespace std; const int N=3e4+10,inf=2147483647/3; struct node{int to,next,w; }a[N*20]; const int dx[5]={1,-1,0,0,0},dy[5]={0,0,1,-1,0}; int n,m,s,t,S,tot=1; int dep[N],ls[N],ans; queue<int> q; void adde(int x,int y,int w){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;return; } bool bfs(){while(!q.empty())q.pop();memset(dep,0,sizeof(dep));dep[s]=1;q.push(s);while(!q.empty()){int x=q.front();q.pop();for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(!a[i].w||dep[y])continue;dep[y]=dep[x]+1;if(y==t)return 1;q.push(y);}}return 0; } int dinic(int x,int flow){int rest=0,k;if(x==t)return flow;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(!a[i].w||dep[y]!=dep[x]+1)continue;rest+=(k=dinic(y,min(flow-rest,a[i].w)));a[i].w-=k;a[i^1].w+=k;if(rest==flow)return flow;}if(!rest)dep[x]=0;return rest; } int main() {scanf("%d%d",&n,&m);S=n*m;s=p(n,m,2)+1;t=s+1;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;scanf("%d",&x);adde(s,p(i,j,0),x);ans+=x;}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;scanf("%d",&x);adde(p(i,j,0),t,x);ans+=x;}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;scanf("%d",&x);adde(s,p(i,j,1),x);ans+=x;for(int k=0;k<5;k++){int zx=i+dx[k],zy=j+dy[k];if(zx<1||zy<1||zx>n||zy>m)continue;adde(p(i,j,1),p(zx,zy,0),inf);}}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){int x;scanf("%d",&x);adde(p(i,j,2),t,x);ans+=x;for(int k=0;k<5;k++){int zx=i+dx[k],zy=j+dy[k];if(zx<1||zy<1||zx>n||zy>m)continue;adde(p(zx,zy,0),p(i,j,2),inf);}}while(bfs())ans-=dinic(s,inf);printf("%d",ans); }總結
以上是生活随笔為你收集整理的P4313-文理分科【最小割】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P3166-[CQOI2014]数三角形
- 下一篇: 绝地求生怎么玩 看完就知道了