题意 : 有一个n*m的矩阵,L个伞兵可能落在某些点上,这些点的坐标已知,需要在某些位置安上一些枪,然后每个枪可以将一行或者一列的伞兵击毙。把这种枪安装到不同行的行首、或者不同列的列首,费用都不同。现在已知把激光枪安装到任意位置的费用,总的花费为这些安装了激光枪的行列花费的乘积。
思路 :就是一个最大流问题。Dinic我不会,用的白皮书上的EK算法,嗯,还行,这个建图比较麻烦,就是把行列分开,成为m+n+1个点。嗯,不废话了,还是把大神博客链接弄过来吧,各方面都讲得很详细。
#include <iostream> #include <stdio.h> #include <string.h> #include <queue> #include <math.h> using namespace std; const int maxn = 300 ; const int INF = 99999999 ; double a[maxn],cap[maxn][maxn],flow[maxn][maxn] ; double f ; int p[maxn] ; int m,n,l; void EK(int s) { queue<int>Q ; memset(flow,0,sizeof(flow)) ; f = 0 ; for( ; ; ) { memset(p,-1,sizeof(p)) ; memset(a,0,sizeof(a)) ; a[s] = INF ; Q.push(s) ; while(!Q.empty()) { int u = Q.front() ;Q.pop() ; for(int v = 0 ; v <= m+n+1 ; v++) { if(!a[v] && cap[u][v] > flow[u][v]) { p[v] = u ; Q.push(v) ; a[v] = min(a[u],cap[u][v]-flow[u][v]) ; } } } if(a[m+n+1] == 0) break ; for(int u = m+n+1 ; u != 0 ; u = p[u]) { flow[p[u]][u] += a[m+n+1] ; flow[u][p[u]] -= a[m+n+1] ; } f += a[m+n+1] ; } } int main() { int T; scanf("%d",&T) ; while(T--) { memset(cap,0,sizeof(cap)) ; f = 0 ; double s ; int x,y ; scanf("%d %d %d",&m,&n,&l) ; for(int i = 1 ; i <= m ; i++) { scanf("%lf",&s) ; cap[0][i] = log(s) ; } for(int i = m+1 ; i <= m+n ; i++) { scanf("%lf",&s) ; cap[i][m+n+1] = log(s) ; } for(int i = 0 ; i < l ; i++) { scanf("%d %d",&x,&y) ; cap[x][m+y] = INF ; } EK(0) ; printf("%.4f\n",exp(f)) ; } return 0; }