【BZOJ2127】happiness

來源:互聯網
上載者:User

標籤:pos   color   執行個體化   inpu   +=   代碼   tput   main   表示   

 Time Limit: 1000 ms   Memory Limit: 256 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 2
  1 1
  100 110
  1
  1000
Sample Output  1210
  【範例說明】
     兩人都選理,則獲得100+110+1000的喜悅值。
  【資料規模】
           對於100%以內的資料,n,m<=100 所有喜悅值均為小於等於5000的非負整數 Solution

  這種相鄰格子的問題,一般都是考慮兩個相鄰的格子的最小割模型,然後把所有模型疊加起來。

  現在考慮相鄰的兩人$x$和$y$。$x$選文或理的收益是$x_0,x_1$;$y$選文或理的收益是$y_0,y_1$;都選文的收益是$s_0$,都選理的收益是$s_1$。

  那麼從總收益$sum=x_0+x_1+y_0+y_1+s_0+s_1$中減去最小割就是最優解。

  考慮一下邏輯關係:

    (1)如果$x$和$y$都選文,那麼需要割去$x_1,y_1,s_1$

    (2)如果$x$和$y$都選理,那麼需要割去$x_0,y_0,s_0$

    (3)如果$x$文$y$理,那麼需要割去$x_1,y_0,s_0,s_1$

    (4)如果$x$理$y$文,那麼需要割去$x_0,y_1,s_0,s_1$

  發現一個人選一科,必定割掉另外一科的喜悅值。那麼由源點$S$向$x$連$x_0$的邊,向$y$連$y_0$的邊;$x$向匯點$T$連$x_1$的邊,向$y$連$y_1$的邊。

  

   現在,(1)和(2)還差$s_0$和$s_1$未刻畫。因為割掉兩條邊以後貌似圖就徹底分開了,不好再加入新的邊來體現,我們考慮將$s_0$附加在$x_0$與$y_0$上,將$s_1$附加在$x_1$與$y_1$上,即各分一半:

   

  (1)和(2)刻畫完畢。但是(3)和(4)在其中不適用了。

  如果$x$選文,$y$選理,那麼割去的邊是右上和左下兩條邊,其權值之和是$x_1+\frac{1}{2}s_1+y_0+\frac{1}{2}s_0$,但是我們期望的是$x_1+y_0+s_0+s_1$,不對啊。

  怎麼辦?期望值和當前值一作差,得$\frac{1}{2}s_0+\frac{1}{2}s_1=\frac{1}{2}(s_0+s_1)$。想辦法把它執行個體化!當割去的是右上和左下兩條邊時,已經形成最小割,那麼強行把這條邊塞進去!由$y$向$x$連一條權值為$\frac{1}{2}(s_0+s_1)$的調整邊即可。

  $x$理$y$文同理。

  

  中間的兩條調整邊,僅在二者文理不同的時候起作用。現在這個模型,已經可以刻畫(1)~(4)所有的情況了。

  對全圖進行建模,跑出最小割,用總收益和減去最小割即可。

Important:

  我們不能對於每兩個格子都像如上模型一樣串連$(S,x),(S,y),(x,T),(y,T)$,將總收益和看做每兩個格子的$sum$之和,然後將模型並起來跑。

  為什嗎?因為這樣我們會發現某一些$x_0$、$x_1$和$y_0$、$y_1$被多算了幾次,這是極不好的,模型之間出現了交集。

  事實上對於一個點$x$,我們將所有$S$->$x$的邊都合并起來:即權值應該為:$x_0$或$y_0$加上$\frac{1}{2} \sum s_0$。$x$到$T$的邊同理。

  而中間的調整邊照常即可。

  這樣當$sum$為所有格子的收益和的時候,用$sum$減去最小割的答案是對的。

Tips:

  可以將邊權乘上2,跑出最小割後除以2,即可忽略小數。

#include <cstdio>#include <queue>using namespace std;const int N=10010,INF=2147000000;int n,m,a[110][110],b[110][110],ax[110][110],ay[110][110],bx[110][110],by[110][110];int sum;int S,T,dis[N],cur[N],h[N],tot;queue<int> q;struct Edge{int v,next,f;}g[N*20];inline int id(int x,int y){return (x-1)*m+y;}inline int min(int x,int y){return x<y?x:y;}inline void addEdge(int u,int v,int f){    g[++tot].v=v; g[tot].f=f; g[tot].next=h[u]; h[u]=tot;    g[++tot].v=u; g[tot].f=0; g[tot].next=h[v]; h[v]=tot;}bool bfs(){    while(!q.empty()) q.pop();    q.push(S);    for(int i=1;i<=T;i++) dis[i]=-1;    dis[S]=0;    while(!q.empty()){        int u=q.front(); q.pop();        for(int i=h[u],v;i;i=g[i].next)            if(g[i].f&&dis[v=g[i].v]==-1){                dis[v]=dis[u]+1;                if(v==T) return true;                q.push(v);            }    }    return dis[T]!=-1;}int dfs(int u,int delta){    if(u==T) return delta;    int ret=0,get;    for(int i=cur[u],v;i&&delta;i=g[i].next)        if(g[i].f&&dis[v=g[i].v]==dis[u]+1){            get=dfs(v,min(delta,g[i].f));            g[i].f-=get;            g[i^1].f+=get;            if(g[i].f) cur[u]=i;            delta-=get;            ret+=get;        }    if(!ret) dis[u]=-1;    return ret;}int dinic(){    int ret=0;    while(bfs()){        for(int i=1;i<=T;i++) cur[i]=h[i];        ret+=dfs(S,INF);    }    return ret;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]),sum+=a[i][j];    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&b[i][j]),sum+=b[i][j];    for(int i=1;i<n;i++) for(int j=1;j<=m;j++) scanf("%d",&ax[i][j]),sum+=ax[i][j];    for(int i=1;i<n;i++) for(int j=1;j<=m;j++) scanf("%d",&bx[i][j]),sum+=bx[i][j];    for(int i=1;i<=n;i++) for(int j=1;j<m;j++) scanf("%d",&ay[i][j]),sum+=ay[i][j];    for(int i=1;i<=n;i++) for(int j=1;j<m;j++) scanf("%d",&by[i][j]),sum+=by[i][j];    S=n*m+1; T=n*m+2; tot=1;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++){            int u=id(i,j);            addEdge(S,u,a[i][j]*2+ax[i-1][j]+ax[i][j]+ay[i][j-1]+ay[i][j]);            addEdge(u,T,b[i][j]*2+bx[i-1][j]+bx[i][j]+by[i][j-1]+by[i][j]);            if(i<n){                addEdge(u,id(i+1,j),ax[i][j]+bx[i][j]);                addEdge(id(i+1,j),u,ax[i][j]+bx[i][j]);            }            if(j<m){                addEdge(u,id(i,j+1),ay[i][j]+by[i][j]);                addEdge(id(i,j+1),u,ay[i][j]+by[i][j]);            }        }    int get=dinic();    get/=2;    printf("%d\n",sum-get);    return 0;}
奇妙代碼

 

【BZOJ2127】happiness

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.