BZOJ3894: 文理分科
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3894: 文理分科相关的知识,希望对你有一定的参考价值。
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
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; }
以上是关于BZOJ3894: 文理分科的主要内容,如果未能解决你的问题,请参考以下文章