码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ3894: 文理分科

时间:2016-03-24 19:59:17      阅读:297      评论:0      收藏:0      [点我收藏+]

标签:

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[n]=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;
}
View Code

 

BZOJ3894: 文理分科

标签:

原文地址:http://www.cnblogs.com/wzj-is-a-juruo/p/5316681.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!