【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

 

原文地址:https://www.cnblogs.com/BearChild/p/6506897.html