您的位置:首页 > 其它

BZOJ3894: 文理分科

2016-03-24 18:47 363 查看

Description

文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠
结过)
小P所在的班级要进行文理分科。他的班级可以用一个n*m的矩阵进行
描述,每个格子代表一个同学的座位。每位同学必须从文科和理科中选择
一科。同学们在选择科目的时候会获得一个满意值。满意值按如下的方式
得到:
1.如果第i行第秒J的同学选择了文科,则他将获得art[i][j]的满意值,如
果选择理科,将得到science[i][j]的满意值。
2.如果第i行第J列的同学选择了文科,并且他相邻(两个格子相邻当且
仅当它们拥有一条相同的边)的同学全部选择了文科,则他会更开
心,所以会增加same_art[i][j]的满意值。
3.如果第i行第j列的同学选择了理科,并且他相邻的同学全部选择了理
科,则增加same_science[i]j[]的满意值。
小P想知道,大家应该如何选择,才能使所有人的满意值之和最大。请
告诉他这个最大值。

Input

第一行为两个正整数:n,m
接下来n术m个整数,表示art[i][j];
接下来n术m个整数.表示science[i][j];
接下来n术m个整数,表示same_art[i][j];

Output

输出为一个整数,表示最大的满意值之和

Sample Input

3 4

13 2 4 13

7 13 8 12

18 17 0 5

8 13 15 4

11 3 8 11

11 18 6 5

1 2 3 4

4 2 3 2

3 1 0 4

3 2 3 2

0 2 2 1

0 2 4 4

Sample Output

152

HINT

样例说明

1表示选择文科,0表示选择理科,方案如下:

1 0 0 1

0 1 0 0

1 0 0 0

N,M<=100,读入数据均<=500

这不全的题目描述是SMG。
先把收益都加进来,然后想办法最小割建模。
我们设S割的节点表示选文,T割的节点表示选理。所以对于每个点x,从S到x连一条容量为art的边,从x到T连一条容量为science的边。
不难发现,如果想要满足一个对x而言的same_art条件,x及与x相邻的节点都不能属于T割,所以可以新建一个节点q,从S到q连一条容量为same_art的边,并从q向x及与x相邻的节点连上一条容量为inf的边。
same_science条件同理。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
if(head==tail) {
int l=fread(buffer,1,BufferSize,stdin);
tail=(head=buffer)+l;
}
return *head++;
}
inline int read() {
int x=0,f=1;char c=Getchar();
for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=30010;
const int maxm=1000010;
const int inf=1e9;
struct ISAP{
struct tedge{int x,y,w,next;}adj[maxm];int ms,fch[maxn];
int d[maxn],s[maxn],cur[maxn],gap[maxn],n,top;
void init(int n){
this->n=n;ms=0;top=0;
memset(d,-1,sizeof(d));
memset(fch,-1,sizeof(fch));
return;
}
void AddEdge(int u,int v,int w){
adj[ms]=(tedge){u,v,w,fch[u]};fch[u]=ms++;
adj[ms]=(tedge){v,u,0,fch[v]};fch[v]=ms++;
return;
}
void bfs(){
queue<int>Q;Q.push(n);d
=0;
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=fch[u];i!=-1;i=adj[i].next){
int v=adj[i].y;
if(d[v]==-1) d[v]=d[u]+1,Q.push(v);
}
} return;
}
int solve(int S,int T){
n=T;bfs();int k=S,i,flow=0;
for(i=0;i<=n;i++) cur[i]=fch[i],gap[d[i]]++;
while(d[S]<n){
if(k==n){
int mi=inf,pos;
for(i=0;i<top;i++) if(adj[s[i]].w<mi) mi=adj[s[i]].w,pos=i;
for(i=0;i<top;i++) adj[s[i]].w-=mi,adj[s[i]^1].w+=mi;
flow+=mi;top=pos;k=adj[s[top]].x;
}
for(i=cur[k];i!=-1;i=adj[i].next){
int v=adj[i].y;
if(adj[i].w&&d[k]==d[v]+1){cur[k]=i;k=v;s[top++]=i;break;}
}
if(i==-1){
int lim=n;
for(i=fch[k];i!=-1;i=adj[i].next){
int v=adj[i].y;
if(adj[i].w&&d[v]<lim) lim=d[v],cur[k]=i;
} if(--gap[d[k]]==0) break;
d[k]=lim+1;gap[d[k]]++;
if(k!=S) k=adj[s[--top]].x;
}
} return flow;
}
}sol;
int n,m,sum,v;
int id(int x,int y,int t) {return t*n*m+(x-1)*m+y;}
const int mx[]={0,1,-1,0,0};
const int my[]={0,0,0,1,-1};
int main() {
n=read(),m=read();
int S=n*m*3+1,T=n*m*3+2;sol.init(T);
rep(i,1,n) rep(j,1,m) sol.AddEdge(S,id(i,j,0),v=read()),sum+=v;
rep(i,1,n) rep(j,1,m) sol.AddEdge(id(i,j,0),T,v=read()),sum+=v;
rep(i,1,n) rep(j,1,m) {
sol.AddEdge(S,id(i,j,1),v=read());sum+=v;
rep(dir,0,4) {
int nx=i+mx[dir],ny=j+my[dir];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(i,j,1),id(nx,ny,0),inf);
}
}
rep(i,1,n) rep(j,1,m) {
sol.AddEdge(id(i,j,2),T,v=read());sum+=v;
rep(dir,0,4) {
int nx=i+mx[dir],ny=j+my[dir];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m) sol.AddEdge(id(nx,ny,0),id(i,j,2),inf);
}
}
printf("%d\n",sum-sol.solve(S,T));
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: