题目链接

 

题意 : 有一个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;
}
View Code

 

posted on 2014-02-18 20:08  枫、  阅读(236)  评论(0编辑  收藏  举报