[BZOJ2127] hapiness
happiness
Time Limit: 51 Sec Memory Limit: 259 MBDescription
高一一班的座位表是个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 1
100 110
1
1000
Sample Output
【样例说明】
两人都选理,则获得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\n",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\n",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\n"); 185 return 0; 186 } 187 work(); 188 return 0; 189 190 }