E - tower HYSBZ - 4657 (网络流割点)
题目链接:https://cn.vjudge.net/contest/281959#problem/E
题目大意:中文题目
具体思路:首先,有矛盾的时候就是两个导弹的运动轨迹会相交的时候,那么我们可以按照这样的思路,在每个导弹不想交的前提下,使得总的消灭数最大。然后我们就可以了按照会相交的方式建图,求出最小割,然后再用总和减去最小割,就能得出最大的消灭量了。
建图的时候,首先横点向竖点连边,权值是inf。每一个炮弹记录他能打到的最大的消灭数,然后对于横着的炮台,从当前的炮台出发到最大的消灭数所在的位置,每一步的权值就是max-当前这个点的权值,最终求的答案的时候,所有炮台的最大值的总和-最小割就是最大消灭数了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<queue> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<cstring> 7 #include<cstring> 8 #include<cmath> 9 #include<algorithm> 10 #include<map> 11 #include<vector> 12 using namespace std; 13 # define ll long long 14 const int maxn = 50000+100; 15 const int inf = 0x3f3f3f3f; 16 int prev[maxn]; 17 int head[maxn]; 18 int dx[10]= {-1,1,0,0}; 19 int dy[10]= {0,0,-1,1}; 20 int A[600][600],B[600][600],w[600][600]; 21 struct node 22 { 23 int to; 24 int flow; 25 int nex; 26 } edge[maxn]; 27 int num,st,ed; 28 void init() 29 { 30 memset(head,-1,sizeof(head)); 31 num=0; 32 } 33 void addedge(int fr,int to,int flow) 34 { 35 edge[num].to=to; 36 edge[num].flow=flow; 37 edge[num].nex=head[fr]; 38 head[fr]=num++; 39 edge[num].to=fr; 40 edge[num].flow=0; 41 edge[num].nex=head[to]; 42 head[to]=num++; 43 } 44 bool bfs() 45 { 46 memset(prev,-1,sizeof(prev)); 47 prev[st]=1; 48 queue<int>q; 49 q.push(st); 50 while(!q.empty()) 51 { 52 int top=q.front(); 53 q.pop(); 54 for(int i=head[top]; i!=-1; i=edge[i].nex) 55 { 56 int temp=edge[i].to; 57 if(prev[temp]==-1&&edge[i].flow>0) 58 { 59 prev[temp]=prev[top]+1; 60 q.push(temp); 61 } 62 } 63 } 64 return prev[ed]!=-1; 65 } 66 int dfs(int u,int flow) 67 { 68 if(u==ed) 69 return flow; 70 int res=0; 71 for(int i=head[u]; i!=-1; i=edge[i].nex) 72 { 73 int t=edge[i].to; 74 if(prev[t]==(prev[u]+1)&&edge[i].flow>0) 75 { 76 int temp=dfs(t,min(flow,edge[i].flow)); 77 edge[i].flow-=temp; 78 edge[i^1].flow+=temp; 79 res+=temp; 80 flow-=temp; 81 if(flow==0) 82 break; 83 } 84 } 85 if(res==0) 86 prev[u]=-1; 87 return res; 88 } 89 int n,m; 90 int dinic() 91 { 92 int ans=0; 93 while(bfs()) 94 { 95 ans+=dfs(st,inf); 96 } 97 return ans; 98 } 99 int cal() 100 { 101 int ans=0,x,y; 102 for (int i = 1; i <= n; i++) 103 for (int j = 1; j <= m; j++) 104 { 105 if (w[i][j] >= 0) continue; 106 int dir = -(w[i][j] + 1),Max = w[i][j] = 0; 107 for (int x = i + dx[dir],y = j + dy[dir]; ;) 108 { 109 if (x < 1 || x > n || y < 1 || y > m) break; 110 Max = max(Max,w[x][y]); x += dx[dir]; y += dy[dir]; 111 } 112 ans += Max; 113 if (dir <= 1) 114 { 115 addedge(st,A[i][j],inf); 116 for (int x = i + dx[dir],y = j + dy[dir]; ;) 117 { 118 if (x < 1 || x > n || y < 1 || y > m) break; 119 addedge(A[x - dx[dir]][y - dy[dir]],A[x][y],Max - w[x - dx[dir]][y - dy[dir]]); 120 x += dx[dir]; y += dy[dir]; 121 } 122 } 123 else 124 { 125 addedge(B[i][j],ed,inf); 126 for (int x = i + dx[dir],y = j + dy[dir]; ;) 127 { 128 if (x < 1 || x > n || y < 1 || y > m) break; 129 addedge(B[x][y],B[x - dx[dir]][y - dy[dir]],Max - w[x - dx[dir]][y - dy[dir]]); 130 x += dx[dir]; y += dy[dir]; 131 } 132 } 133 } 134 return ans; 135 } 136 int main() 137 { 138 init(); 139 int tot=0; 140 scanf("%d %d",&n,&m); 141 for(int i=1; i<=n; i++) 142 { 143 for(int j=1; j<=m; j++) 144 { 145 A[i][j]=++tot,B[i][j]=++tot; 146 scanf("%d",&w[i][j]); 147 addedge(A[i][j],B[i][j],inf); 148 } 149 } 150 st=++tot,ed=++tot; 151 int sum=cal(); 152 int ans=dinic(); 153 // cout<<sum<<" "<<ans<<endl; 154 printf("%d\n",sum-ans); 155 return 0; 156 }