zoukankan      html  css  js  c++  java
  • HDU1565 方格取数(1)

    Problem Description
    给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
    从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
     
    Input
    包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)
     
    Output
    对于每个测试实例,输出可能取得的最大的和
     
    Sample Input
    3 75 15 21 75 15 28 34 70 5
    Sample Output
    188
    Author
    ailyanlu
    Source
     
     
    正解:网络流
    解题报告:
      网络流24题第9题。同样是可以转换为最大点权和独立集,求最小割跑最大流。自己的题解:

      模型:建图+最小割

      总结:

      和前面做的几道题很类似,都是求最大独立集。事实上都可以转换成二分图,然后按照最小割模型来做。

      考虑这道题说不能选取有相邻边的格子中的数,相当于是如果选取了当前格子,那么周围相邻的四个格子都不能再选。这个模型显然就是一个二分图,所以首先我们可以先把全图进行二分图染色,对于一个点坐标为(ij),如果(i+j%2==0,那么染成白色;否则,染成黑色。然后新建源点S,向所有白色点连一条容量为该点点权的有向边;新建汇点T,所有黑色点连一条容量为该点点权的有向边。对于所有白色点,向四周的所有黑色点都连一条容量为无穷的有向边。如此以来我们构出了一张图(跟前几道题一样的说)

      显然我们希望得到选取的尽可能多的格子,由于都是正数所以肯定能选尽量选。但是如果选了一个格子,就意味着四周的全都不能再选了,也就是说如果我们把ans初值记为所有格子权值之和,那么我们每次因为选择了一个格子就会失去周围四个的权值,需要从ans中减掉。这跟什么很像呢?最大半连通子图!是的,一样的做法,用总的和减去最小割就可以得到我们期望的最大值。

      
     
      1 //It is made by jump~
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <algorithm>
      8 #include <ctime>
      9 #include <vector>
     10 #include <queue>
     11 #include <map>
     12 #include <set>
     13 #ifdef WIN32   
     14 #define OT "%I64d"
     15 #else
     16 #define OT "%lld"
     17 #endif
     18 using namespace std;
     19 typedef long long LL;
     20 const int MAXN = 501;
     21 const int MAXM = 500011;
     22 const int inf = (1<<30);
     23 int n,sum,S,T,ecnt,ans;
     24 int a[MAXN][MAXN],deep[MAXN*MAXN];
     25 int first[MAXN*MAXN];
     26 queue<int>Q;
     27 struct edge{
     28     int next,to,f;
     29 }e[MAXM];
     30 
     31 inline int getint()
     32 {
     33        int w=0,q=0;
     34        char c=getchar();
     35        while((c<'0' || c>'9') && c!='-') c=getchar();
     36        if (c=='-')  q=1, c=getchar();
     37        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
     38        return q ? -w : w;
     39 }
     40 
     41 inline void link(int x,int y,int z){
     42     e[++ecnt].next=first[x]; first[x]=ecnt; e[ecnt].to=y; e[ecnt].f=z;
     43     e[++ecnt].next=first[y]; first[y]=ecnt; e[ecnt].to=x; e[ecnt].f=0;
     44 }
     45 
     46 inline bool bfs(){
     47     while(!Q.empty()) Q.pop();
     48     for(int i=1;i<=T;i++) deep[i]=0;
     49     Q.push(S); deep[S]=1;
     50     while(!Q.empty()) {
     51     int u=Q.front(); Q.pop();
     52     for(int i=first[u];i;i=e[i].next) {
     53         int v=e[i].to;
     54         if(e[i].f && !deep[v]) deep[v]=deep[u]+1,Q.push(v);
     55     }
     56     }
     57     if(deep[T]!=0) return true;
     58     return false;
     59 }
     60 
     61 inline int Dinic(int x,int remain){
     62     if(remain==0 || x==T) return remain;
     63     int f,flow=0;
     64     for(int i=first[x];i;i=e[i].next) {
     65     int v=e[i].to;
     66     if(e[i].f && deep[v]==deep[x]+1){
     67         f=Dinic(v,min(remain,e[i].f));
     68         if(f){
     69         flow+=f; e[i].f-=f; e[i^1].f+=f;
     70         remain-=f; if(remain==0) return flow;
     71         } else deep[v]=-1;
     72     }
     73     }
     74     return flow;
     75 }
     76 
     77 inline void work(){
     78     while(scanf("%d",&n)!=EOF) {
     79     sum=0;
     80     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)   a[i][j]=getint(),sum+=a[i][j];
     81     S=n*n+1;T=S+1; ecnt=1; memset(first,0,sizeof(first));
     82     for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if((i+j)%2==0) link(S,(i-1)*n+j,a[i][j]); else link((i-1)*n+j,T,a[i][j]);//黑白染色
     83     for(int i=1;i<=n;i++) 
     84         for(int j=1;j<=n;j++){
     85         if((i+j)%2) continue;
     86         if(i!=1) link((i-1)*n+j,(i-2)*n+j,inf);     
     87         if(j!=1) link((i-1)*n+j,(i-1)*n+j-1,inf);
     88         if(j!=n) link((i-1)*n+j,(i-1)*n+j+1,inf);
     89         if(i!=n) link((i-1)*n+j,i*n+j,inf);
     90         }
     91     ans=0;
     92     while(bfs()) ans+=Dinic(S,inf);
     93     printf("%d
    ",sum-ans);
     94     }
     95 }
     96 
     97 int main()
     98 {
     99   work();
    100   return 0;
    101 }
  • 相关阅读:
    java 变量常量作用域
    简述Integer
    简述(非)静态代码块和构造方法的执行顺序
    父类子类在有(无)参构造方法继承的一些规则
    equals和==的区别
    创建和调用自定义类的方法简述
    int变量与double变量混合运算时的常见问题及方法
    int变量运算过程中的常见问题及方法
    初始Java
    Eclipse常用快捷键
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5756667.html
Copyright © 2011-2022 走看看