• 【BZOJ4657】tower [网络流]


    炮塔

    Time Limit: 10 Sec  Memory Limit: 256 MB

    Description

      

    Input

      

    Output

      一行一个整数表示答案。

    Sample Input

      4 5
      0 0 -2 0 0
      -4 0 5 4 0
      0 -4 3 0 6
      9 0 0 -1 0

    Sample Output

      12

    HINT

      

    Main idea

      给定若干固定方向的炮台,以及若干位置的敌人,炮台可以杀掉对应方向上从该位置到底的其中一个位置的敌人,要求炮台位置和消灭的敌人位置连线,连线不能有重叠,询问最多能消灭几个敌人。

    Solution

      我们发现,相交的连线其实就是给出了炮台之间的路径。我们来处理如何解决无可走路径的问题,显然想到了最小割

      横向炮台或纵向炮台之间是没有影响的。所以显然可以构建一张二分图

      那么我们如何确定容量呢?我们可以令一条 (u->v) 的割边表示选择了u这个点。方便处理连边上下或左右攻击的炮台,连边方向应该一致。然后我们连边时先找到一条可攻击位置上的最大贡献,设最大贡献为Max,然后连边时容量用Max-val,就表示它会损失这么多的价值。注意到这样连边的话,在最边界上的点是没有连边的。但是并不会影响答案,为什么呢?我们这么考虑:如果我们选择了最边界的点,那么这个位置的敌人数必然是最多的,如果不是最多的话(也就是说还有其它点人数更多)显然连到边界不可能是最优的,因为连边界就可能阻断了更多其它炮台攻击方案的可能性。这就表示了,若选择边界,则必然边界贡献最多,那么如果连边了,容量也应该是0,综上所述不会影响答案。

      我们这样连完了边,但发现还是会有一些问题。如果出现这种情况,就会有一些Bug:

      这样就会影响了答案。怎么处理呢?我们发现问题只能涉及一行一列,只要令路径只能“拐一次弯”就可以解决。所以我们可以再将点拆为横向点和纵向点,横向点向纵向点连INF的边,纵向点没有边连向横向点即可。

      这样的话复杂度就是O(maxflow(n×m,n×m)),成功了解决了问题!(≧▽≦)/

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>  
      7 using namespace std;
      8 
      9 const int ONE = 100001;
     10 const int INF = 214783640;
     11 
     12 int n,m;
     13 int S,T;
     14 int Ans;
     15 int a[101][101],Max;
     16 int next[ONE],first[ONE],go[ONE],w[ONE],tot;
     17 int q[10000001],Dep[ONE],E[ONE],tou,wei;
     18 #define id(i,j) (i-1)*m+j
     19 
     20 int get()
     21 { 
     22         int res,Q=1;    char c;
     23         while( (c=getchar())<48 || c>57)
     24         if(c=='-')Q=-1;
     25         if(Q) res=c-48; 
     26         while((c=getchar())>=48 && c<=57) 
     27         res=res*10+c-48; 
     28         return res*Q; 
     29 }
     30 
     31 void Add(int u,int v,int z)
     32 {
     33         next[++tot]=first[u];    first[u]=tot;    go[tot]=v;    w[tot]=z;
     34         next[++tot]=first[v];    first[v]=tot;    go[tot]=u;    w[tot]=0;
     35 }
     36 
     37 int Bfs()
     38 {
     39         memset(Dep,0,sizeof(Dep));
     40         tou=0;    wei=1;
     41         q[1]=S;    Dep[S]=1;
     42         for(int u=S;u<=T;u++) E[u]=first[u]; 
     43         while(tou < wei)
     44         {
     45             int u=q[++tou];
     46             for(int e=first[u];e;e=next[e])
     47             {
     48                 int v=go[e];
     49                 if(Dep[v] || !w[e]) continue;
     50                 Dep[v] = Dep[u] + 1;
     51                 q[++wei] = v;
     52             }
     53         }
     54         return Dep[T] > 0;
     55 }
     56 
     57 int Dfs(int u,int Limit)
     58 {
     59         if(u==T || !Limit) return Limit;
     60         int flow=0,f;
     61         for(int &e=E[u]; e; e=next[e])
     62         {
     63             int v=go[e];
     64             if(Dep[v]!=Dep[u]+1 || !w[e]) continue;
     65             f=Dfs(v,min(w[e],Limit));
     66             w[e] -= f;
     67             w[((e-1)^1)+1] += f;
     68             Limit -= f;
     69             flow += f;
     70             if (!Limit) break;
     71         }
     72         return flow;
     73 }
     74 
     75 int main()
     76 {      
     77         n=get();    m=get();
     78         for(int i=1;i<=n;i++)
     79         for(int j=1;j<=m;j++)
     80         {
     81             a[i][j] = get();
     82         }
     83         
     84         int PD=n*m;
     85         S=0;    T=2*PD+1;
     86         for(int i=1;i<=n;i++)
     87         for(int j=1;j<=m;j++)
     88         {
     89             if(a[i][j] == -1)
     90             {
     91                 Max = a[i][j] = 0;
     92                 Add(S,id(i,j),INF);
     93                 for(int k=i-1;k>=1;k--) Max = max(Max, a[k][j]);
     94                 for(int k=i;k>=1+1;k--) Add(id(k,j), id(k-1,j), Max-a[k][j]);
     95                 Ans += Max;
     96             }
     97             
     98             else
     99             if(a[i][j] == -2)
    100             {
    101                 Max = a[i][j] = 0;
    102                 Add(S,id(i,j),INF);
    103                 for(int k=i+1;k<=n;k++)    Max = max(Max, a[k][j]);
    104                 for(int k=i;k<=n-1;k++) Add(id(k,j), id(k+1,j), Max-a[k][j]);
    105                 Ans += Max;
    106             }
    107             
    108             else
    109             if(a[i][j] == -3)
    110             {
    111                 Max = a[i][j] = 0;
    112                 Add(id(i,j)+PD,T,INF);
    113                 for(int k=j-1;k>=1;k--) Max = max(Max, a[i][k]);
    114                 for(int k=j;k>=1+1;k--) Add(id(i,k-1)+PD, id(i,k)+PD, Max-a[i][k]);
    115                 Ans += Max;
    116             }
    117             
    118             else
    119             if(a[i][j] == -4)
    120             {
    121                 Max = a[i][j] = 0;
    122                 Add(id(i,j)+PD,T,INF);
    123                 for(int k=j+1;k<=m;k++) Max = max(Max, a[i][k]);
    124                 for(int k=j;k<=m-1;k++) Add(id(i,k+1)+PD, id(i,k)+PD, Max-a[i][k]);
    125                 Ans += Max;
    126             }
    127             
    128             else
    129             {
    130                 Add(id(i,j), id(i,j)+PD, INF);
    131             }
    132         }
    133         
    134         while(Bfs()) Ans-=Dfs(S,INF);
    135         
    136         printf("%d",Ans); 
    137 }
    View Code

     

  • 相关阅读:
    无刷新跨域上传图片
    php框架-yii
    nginx-url重写
    linux下挂载移动硬盘ntfs格式
    页面有什么隐藏bug:字体,图片
    Oracle、MySql、SQLServer数据分页查询
    转载:Qt之界面实现技巧
    QT常用资料
    MySQL判断字段值来确定是否插入新记录
    WindowsAPI开发常用资料
  • 原文地址:https://www.cnblogs.com/BearChild/p/6506897.html
Copyright © 2020-2023  润新知