hdu 1569 and hdu 3657 最小割

hdu1569

给你一个m*n的格子的棋盘,每个格子里面有一个非负数。

从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。

按国际象棋黑白染色,源点到黑点容量为数字,黑点到它周围的白点容量为无穷,白点到汇点容量为数字,最后答案为总值减去最小割(摘自网上)。

(行+列)= 奇数 黑子   连T

(行+列)= 偶数 白子   连S

没有黑白相邻 , 意味着 ,S 到T没有路可走。 否则 S->黑->白->T 。

<=>  最小的花费把S-T之间的路切开。 

U - V 分开最小的权和, 也就是求最小割。

为啥黑->白权值设为inf  ?

这条边“死都存在”,不能人为的移走,那么就是“死都存在”。

意味着不能切割黑->白之间的边。 


int  main(){
     int n , m  , i , j ,  u , v , c , sum ;
     while(scanf("%d%d" ,&n ,&m) != EOF){
          init() ;
          sum = 0 ;
          sourse = 0 ;
          meet = n*m + 1 ;
          for(i = 1 ; i <= n ; i++){
              for(j = 1 ; j <= m ; j++){
                   scanf("%d" ,&c) ;
                   sum += c ;
                   u = (i-1) * m + j ;
                   if((i+j)&1)
                        add(u , meet , c) ;
                   else{
                        add(sourse , u , c) ;
                        if(i > 1)
                             add(u , u-m , inf) ;
                        if(i < n)
                             add(u , u+m , inf) ;
                        if(j > 1)
                             add(u , u-1 , inf) ;
                        if(j < m)
                             add(u , u+1 , inf) ;
                   }
              }
          }
          printf("%d\n" , sum - maxflow()) ;
     }
     return 0 ;
}

 hdu 3657 

题目描述:n*m的矩阵,每个位置都有一个正数,一开始你的分数是0,当你取走一个数字时,你的分数增加那个分数。如果你取完数字后,新出现了2个相邻的都是空的格子,那么你的分数减少2 * ( x & y),x,y是那两个格子的原始数值。

同时有一些附加条件,有一些格子的数字是必须拿走的。

-----------------------

同上题

----------------------

为啥将黑->白权值设为2*(x&y) 

因为切割黑-白之间的路可以“人为的移走”,不是“死都存在”的边。

对于必须选择的棋子,将权值设为inf。也就是说最小割集不会选择此边<=>此点必选。



int  w[58][58] ;
bool is[58][58] ;

int  main(){
     int n , m , i , j  , k , u  , sum ;
     while(cin>>n>>m>>k){
          sum = 0 ;
          init() ;
          sourse = 0 , meet = n*m + 1 ;
          for(i = 1 ; i <= n ; i++){
             for(j = 1 ; j <= m ; j++){
                 scanf("%d" ,&w[i][j]) ;
                 sum += w[i][j] ;
             }
          }
          memset(is , 0 , sizeof(is)) ;
          while(k--){
               scanf("%d%d" ,&i ,&j) ;
               is[i][j] = 1 ;
          }
          for(i = 1 ; i <= n ; i++){
              for(j = 1 ; j <= m ; j++){
                  u = (i-1)*m + j ;
                  if((i+j)&1){
                      if(is[i][j])
                          add(u , meet , inf) ;
                      else
                          add(u , meet , w[i][j]) ;
                  }
                  else{
                      if(is[i][j])
                         add(sourse , u , inf) ;
                      else
                         add(sourse , u , w[i][j]) ;
                      if(i > 1)
                         add(u , u-m , 2*(w[i][j]&w[i-1][j])) ;
                      if(i < n)
                         add(u , u+m , 2*(w[i][j]&w[i+1][j])) ;
                      if(j > 1)
                         add(u , u-1 , 2*(w[i][j]&w[i][j-1])) ;
                      if(j < m)
                         add(u , u+1 , 2*(w[i][j]&w[i][j+1])) ;
                  }
              }
          }
          printf("%d\n" , sum - maxflow()) ;
     }
     return 0 ;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值