poj 3308(二分图的点权最小覆盖)

Paratroopers
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 8325   Accepted: 2502

Description

It is year 2500 A.D. and there is a terrible war between the forces of the Earth and the Mars. Recently, the commanders of the Earth are informed by their spies that the invaders of Mars want to land some paratroopers in the m × n grid yard of one their main weapon factories in order to destroy it. In addition, the spies informed them the row and column of the places in the yard in which each paratrooper will land. Since the paratroopers are very strong and well-organized, even one of them, if survived, can complete the mission and destroy the whole factory. As a result, the defense force of the Earth must kill all of them simultaneously after their landing.

In order to accomplish this task, the defense force wants to utilize some of their most hi-tech laser guns. They can install a gun on a row (resp. column) and by firing this gun all paratroopers landed in this row (resp. column) will die. The cost of installing a gun in the ith row (resp. column) of the grid yard is ri (resp. ci ) and the total cost of constructing a system firing all guns simultaneously is equal to the product of their costs. Now, your team as a high rank defense group must select the guns that can kill all paratroopers and yield minimum total cost of constructing the firing system.

Input

Input begins with a number T showing the number of test cases and then, T test cases follow. Each test case begins with a line containing three integers 1 ≤ m ≤ 50 , 1 ≤ n ≤ 50 and 1 ≤ l ≤ 500 showing the number of rows and columns of the yard and the number of paratroopers respectively. After that, a line with m positive real numbers greater or equal to 1.0 comes where the ith number is ri and then, a line with n positive real numbers greater or equal to 1.0 comes where the ith number is ci. Finally, l lines come each containing the row and column of a paratrooper.

Output

For each test case, your program must output the minimum total cost of constructing the firing system rounded to four digits after the fraction point.

Sample Input

1
4 4 5
2.0 7.0 5.0 2.0
1.5 2.0 2.0 8.0
1 1
2 2
3 3
4 4
1 4

Sample Output

16.0000

题意:一个矩阵,已知其中一些格会降落伞兵,每行每列都有一个武器,可以一次性消灭该行或该列的全部伞兵,每个武器对应不同的价格,若使用多个武器则总价是各个武器价钱的乘积,问消灭所有伞兵最少
要多少钱。
题解:上次看训练指南看到这个题的弱化版了,所以就马上知道用二分图的最小覆盖集来做,只不过这个题加了个条件,武器总价等于各个武器价格的乘积。。然后就卡住了,,结果找题解发现竟然是取对数将乘法
来做变成加法真的是好难想到啊 T_T 想到了就直接用 最小覆盖集 = 最小割 = 最大流来做了。。。
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <string.h>
#include <math.h>
#include <iostream>
#include <math.h>
using namespace std;
const int N = 305;
const int INF = 999999999;
struct Edge{
    int v,next;
    double w;
}edge[N*N];
int head[N];
int level[N];
int tot;
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
void addEdge(int u,int v,double w,int &k){
    edge[k].v = v,edge[k].w=w,edge[k].next=head[u],head[u]=k++;
    edge[k].v = u,edge[k].w=0,edge[k].next=head[v],head[v]=k++;
}
int BFS(int src,int des){
    queue<int >q;
    memset(level,0,sizeof(level));
    level[src]=1;
    q.push(src);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        if(u==des) return 1;
        for(int k = head[u];k!=-1;k=edge[k].next){
            int v = edge[k].v;
            double w = edge[k].w;
            if(level[v]==0&&w!=0){
                level[v]=level[u]+1;
                q.push(v);
            }
        }
    }
    return -1;
}
double dfs(int u,int des,double increaseRoad){
    if(u==des) return increaseRoad;
    double ret=0;
    for(int k=head[u];k!=-1;k=edge[k].next){
        int v = edge[k].v;
        double w = edge[k].w;
        if(level[v]==level[u]+1&&w!=0){
            double MIN = min(increaseRoad-ret,w);
            w = dfs(v,des,MIN);
            edge[k].w -=w;
            edge[k^1].w+=w;
            ret+=w;
            if(ret==increaseRoad) return ret;
        }
    }
    return ret;
}
double Dinic(int src,int des){
    double ans = 0;
    while(BFS(src,des)!=-1) ans+=dfs(src,des,INF*1.0);
    return ans;
}

int main(){
     int tcase;
     scanf("%d",&tcase);
     while(tcase--){
         init();
         int n,m,k;
         double a[50],b[50];
         scanf("%d%d%d",&n,&m,&k);
         int src = 0,des = n+m+1;
         double t;
         for(int i=1;i<=n;i++){
            scanf("%lf",&t);
            addEdge(src,i,log(t),tot);
         }
         for(int i=n+1;i<=n+m;i++){
            scanf("%lf",&t);
            addEdge(i,des,log(t),tot);
         }
         while(k--){
            int u,v;
            scanf("%d%d",&u,&v);
            addEdge(u,v+n,INF*1.0,tot);
         }
         printf("%.4lf
",exp(Dinic(src,des)));
     }
}
原文地址:https://www.cnblogs.com/liyinggang/p/5552296.html