[BZOJ2127] hapiness

happiness

Time Limit: 51 Sec  Memory Limit: 259 MB

Description

高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友。这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值。作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大。

Input

第一行两个正整数n,m。接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值。第二个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择理科获得的喜悦值。第三个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择文科获得的额外喜悦值。第四个矩阵为n-1行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i+1行第j列的同学同时选择理科获得的额外喜悦值。第五个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择文科获得的额外喜悦值。第六个矩阵为n行m-1列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学与第i行第j+1列的同学同时选择理科获得的额外喜悦值。

Output

输出一个整数,表示喜悦值总和的最大值

Sample Input

1 2
1 1
100 110
1
1000

Sample Output

1210
【样例说明】
两人都选理,则获得100+110+1000的喜悦值。
【数据规模】
对于100%以内的数据,n,m<=100 所有喜悦值均为小于等于5000的非负整数

HINT

 

SOLUTION

这道题是一个最小割的问题,但是用到了神奇的构图方法,把源点当做选择文科,汇点是选择理科,以为每一个人都与选择文理科有关,所有显然每个人应该与文科理科都连一条边,但是有的人同选文或理也会有一定的额文喜悦值,在这两个人之间,一定有一个什么边,先假设边是如下图所示

那么在最小割的时候,有可能把右边的两条边割掉,这时两人对答案的贡献是文x,文y,以及两人同选文的喜悦值,文x肯定是要加在1号边上,文y是要加在3号边上,那么现在就是同事选文或理的边权不知道该怎么加,那么我们考虑割掉的2,3号边,我们用的是最小割求最大喜悦值,那么肯定是要用总的所有喜悦值去减掉割出来的喜悦值,那么一定的x,y选理得单独喜悦值减掉了,但是少减得是同理的,那么我们就把他平均分配到两个边上,这样1,2,3,4边权就确定了,我们在考虑割掉的是1,5,4号边,减去的是理x ,文y ,同理,同文,那么根据已确定的边就可已得到5号边的边权是1/2*(同文+同理),而且是双向边(因为可以见3,5,2,)号边,在建边的时候注意变得合并,然后跑一边最大流,再用sum减就行了;

有的时候边权需要自己配置

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define INF 1000000
  9 using namespace std;
 10 
 11 int zhao;
 12 int n,m,peo;
 13 int a[30][30];
 14 int dor[30];
 15 int id[30][30];
 16 int dis[410][410];
 17 int mov[6][3];
 18 int jia;
 19 int S,T;
 20 
 21 struct node{
 22     int u,v,w,nxt;
 23 }g[5000100];
 24 int adj[5000100],e;
 25 void add(int u,int v,int w){
 26     g[e].v=v; g[e].u=u; g[e].w=w;
 27     g[e].nxt=adj[u]; adj[u]=e++;
 28 }
 29 bool Jud(int x,int y,int i,int pos){
 30     int x1=x+mov[i][0] ,y1=y+mov[i][1];
 31     if(!(x1>=1 && x1<=n && y1>=1 && y1<=m)) return 0;
 32     if(a[x1][y1]==0 || a[x1][y1]==2) return 0;
 33     int pos2=(x+mov[i][0]-1)*m+ ( y+mov[i][1] );
 34     if(dis[pos2][pos]<10000) return 0;
 35     return 1; 
 36 }
 37 void find_short(int pos){
 38     queue<int> q;
 39     q.push(pos);
 40     dis[pos][pos]=0;
 41     int k;
 42     int x,y;
 43     while(!q.empty()){
 44         k=q.front(); q.pop();
 45         //cout<<"k== "<<k<<endl;
 46         x=(k-1)/m+1; y=k%m; if(y==0) y=m;
 47         for(int i=1;i<=4;i++){
 48             if(Jud(x,y,i,pos)){
 49                 int pos2=(x+mov[i][0]-1)*m+ ( y+mov[i][1] );
 50                 dis[pos2][pos]=dis[k][pos]+1;
 51                 //cout<<"pos== "<<pos2<<"  "<<pos<<"  "<<dis[pos2][pos]<<endl;
 52                 q.push(pos2);
 53             }
 54         }
 55     }
 56 }
 57 void init(){
 58     scanf("%d%d",&n,&m);
 59     jia=n*n;
 60     char s[30];
 61     for(int i=1;i<=n;i++){
 62         scanf("%s",&s);
 63         for(int j=0;j<m;j++){
 64             if(s[j]=='.')      a[i][j+1]=1,peo++;
 65             else if(s[j]=='X') a[i][j+1]=0;
 66             else if(s[j]=='D') a[i][j+1]=2;
 67         }
 68     }
 69     for(int i=1;i<=n;i++)
 70         for(int j=1;j<=m;j++){
 71             id[i][j]=m*(i-1)+j;
 72             if(a[i][j]==2) dor[++dor[0]]=id[i][j];
 73         }
 74     mov[1][0]=0; mov[1][1]=1;
 75     
 76     mov[2][0]=0; mov[2][1]=-1;
 77     mov[3][0]=1; mov[3][1]=0;
 78     mov[4][0]=-1;mov[4][1]=0;
 79     memset(dis,30,sizeof(dis));
 80     int x,y;
 81     for(int i=1;i<=dor[0];i++){
 82         find_short(dor[i]);
 83     }
 84 }
 85 bool nengpao(){
 86     for(int i=1;i<=n;i++){
 87         for(int j=1;j<=m;j++){
 88             bool ok=0;
 89             if(a[i][j]==0 || a[i][j]==2) continue;
 90             for(int k=1;k<=dor[0];k++){
 91                 if(dis[id[i][j]][dor[k]]<10000) ok=1;
 92             }
 93             if(!ok) return 0;
 94         }
 95     }
 96     return 1;
 97 }
 98 int dep[300010];
 99 bool BFS(){
100     //if(zhao==149) cout<<zhao<<endl;
101     memset(dep,0,sizeof(dep));
102     queue<int> q; int k;
103     dep[S]=1;
104     q.push(S);
105     while(!q.empty()){
106         k=q.front(); q.pop();
107         for(int i=adj[k];i!=-1;i=g[i].nxt){
108             int v=g[i].v;
109             if(g[i].w && !dep[v]){
110                 dep[v]=dep[k]+1;
111                 if(v==T) return 1;
112                 q.push(v);
113             }
114         }
115     }
116     return 0;
117 }
118 int dfs(int x,int fw){
119     //printf("x==%d   fw==%d
",x,fw);
120     if(x==T) return fw;
121     int tmp=fw,k;
122     for(int i=adj[x];i!=-1;i=g[i].nxt){
123         int v=g[i].v;
124         if(g[i].w && tmp && dep[v]==dep[x]+1){
125             k=dfs(v,min(tmp,g[i].w));
126             if(!k){
127                 dep[v]=0;
128                 continue;
129             }
130             g[i].w-=k; g[i^1].w+=k; tmp-=k;
131         }
132     }
133     return fw-tmp;
134 }
135 bool check(int lim){
136     int ch=lim; zhao=lim;
137     memset(adj,-1,sizeof(adj)); e=0;
138     for(int i=1;i<=dor[0];i++){
139         for(int j=1;j<=lim;j++){
140             add((i-1)*ch+j+jia,T,1); add(T,(i-1)*ch+j+jia,0);
141         }
142     }
143     for(int i=1;i<=n;i++){
144         for(int j=1;j<=m;j++){
145             //cout<<"id2=="<<id[i][j]<<endl;
146             if(a[i][j]==0 || a[i][j]==2) continue;
147             //cout<<"id== "<<id[i][j]<<endl;
148             add(S,id[i][j],1); add(id[i][j],S,0);
149             for(int k=1;k<=dor[0];k++){
150                 if(dis[id[i][j]][dor[k]]>10000) continue;
151                 for(int hh=dis[id[i][j]][dor[k]];hh<=lim;hh++){
152                     add(id[i][j],(k-1)*ch+hh+jia,1), add((k-1)*ch+hh+jia,id[i][j],0);
153                     //if(lim==300) cout<<id[i][j]<<"   "<<(k-1)*ch+hh+jia<<endl;
154                 }
155             }
156         }
157     }
158     int he=0,tan;
159     while(BFS()){
160         while(tan=dfs(S,INF)){ he+=tan; }
161     }
162     //cout<<"lim== "<<lim<<"  "<<he<<endl;
163     if(he>=peo) return 1;
164     else return 0;
165     
166 }
167 void work(){
168     S=0; T=300000;
169     int l=0,r=600,mid,ans=600;
170     while(l<=r){
171         mid=(l+r)>>1;
172         if(check(mid)) ans=mid,r=mid-1;
173         else l=mid+1;
174     }
175     printf("%d
",ans);
176     return;
177 }
178 int main(){
179     //freopen("a.in","r",stdin);
180     //freopen("a.out","w",stdout);
181     init();
182     bool ok=nengpao();
183     if(!ok){
184         printf("impossible
");
185         return 0;
186     }
187     work();
188     return 0;
189     
190 }
原文地址:https://www.cnblogs.com/FOXYY/p/7266527.html