POJ 3308

http://poj.org/problem?id=3308

考虑答案不是乘积而是和的做法,

因为对于每一个伞兵我们要么在这行内安装大炮消灭它

要么在这列中安装大炮消灭它,所以容易看出这是一个最小边覆盖集的问题

所以转化成乘积需要用到一个特殊的方法(以前没用过)

\(ans=a_1a_2\cdots a_k\)
\(ans=10^{\lg ans}=10^{\lg a_1a_2\cdots a_k}\)
\(ans=10^{\lg a_1+\lg a_2+\cdots \lg a_k}\)
这样就将乘法转化成加法了

不过还是遇到一个问题不知道如何解决
这个边的流量如果是浮点数如何解决
…………………………………………

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#define N 1000005
#define inf 0x3f3f3f3f
using namespace std;

int read(){
    int s=0;char ch=getchar();
    for(;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);s=s*10+ch-'0',ch=getchar());
    return s;
}

struct Edge{
    int to,nxt,cap;
};

int que[N];
int h,qt;

struct Dinic{
    Edge e[N];
    bool vis[N];
    int tot,s,t,n;
    int d[N],cur[N],head[N];
    Dinic(){tot=1;}
    void add(int u,int v,int f){
        e[++tot].to=v;
        e[tot].cap=f;
        e[tot].nxt=head[u];
        head[u]=tot;
        e[++tot].to=u;
        e[tot].cap=0;
        e[tot].nxt=head[v];
        head[v]=tot;
    }
    bool bfs(){
        memset(vis,false,sizeof(vis));
        for(int i=0;i<=n;++i)cur[i]=head[i];
        que[qt=1]=s,h=0;int top,to;d[s]=0;vis[s]=1;
        while(h<qt){
            top=que[++h];
            for(int i=head[top];i;i=e[i].nxt)
                if(!vis[e[i].to]&&e[i].cap){
                    to=e[i].to;que[++qt]=to;
                    vis[to]=true;d[to]=d[top]+1;
                    if(to==t)return true;
                }
        }
        return vis[t];
    }
    int dfs(int x,int fl){
        if(x==t)return fl;
        int flow=0,f,to;
        for(int &i=cur[x];i;i=e[i].nxt){
            to=e[i].to;
            if(d[to]==d[x]+1&&e[i].cap)
            if(f=dfs(to,min(fl,e[i].cap))){
                e[i].cap-=f;fl-=f;
                e[i^1].cap+=f;flow+=f;
                if(fl<=0)break;
            }
        }
        if(fl)d[x]=-1;
        return flow;
    }
    int maxflow(int s,int t){
        this->s=s;this->t=t;
        int ans=0;
        while(bfs())ans+=dfs(s,inf);
        return ans;
    }
};

int co[N];
int st[N];

double Co[N];
double St[N];

int main(){
    Dinic f;
    int n,m,k,s,t,a,b,c;
    scanf("%d%d%d",&n,&m,&k);
    f.n=2+n+m;
    for(int i=1;i<=n;++i){
        cin>>co[i];
        Co[i]=log10(co[i]);
    }
    for(int i=1;i<=n;++i)
        f.add(1,i+1,Co[i]);
    for(int j=1;j<=m;++j)
        f.add(n+m+2,n+1+i);
    for(int i=1;i<=n;++i){
        cin>>st[i];
        St[i]=log10(st[i]);
    }
    for(int i=1;i<=k;++i){
        cin>>a>>b;
        f.add(a,b,inf);
    }
    cout<<f.maxlflow(1,n+m+2);
    return 0;
}
时间: 2024-10-13 21:27:06

POJ 3308的相关文章

POJ 3308 Paratroopers (二分图最小点权覆盖 -&gt; 最小割 -&gt; 最大流)

POJ 3308 Paratroopers 链接:http://poj.org/problem?id=3308 题意:有一个N*M的方阵,有L个伞兵降落在方阵上.现在要将所有的伞兵都消灭掉,可以在每行每列装一个高射炮,如果在某行(某列)装上高射炮之后,能够消灭所有落在该行(该列)的伞兵.每行每列安高射炮有费用,问如何安装能够使得费用之积最小. 思路:首先题目要求乘积最小,将乘积对e取对数,会发现就变成了求和.然后抽象出一个二分图,每一行是x部的一个点,每个点有权值,权值为费用取ln.每一列是y部

POJ 3308 Paratroopers 最小点权覆盖 求最小割

不懂这个建模是什么原理,以后把二分图相关的东西看完再补上把= = #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #i

zoj 2874 &amp; poj 3308 Paratroopers (最小割)

题意: 一个m*n大小的网格,已知伞兵着陆的具体位置(行和列).现在在某行(或某列) 安装一架激光枪,一架激光枪能杀死该行(或该列)所有的伞兵.在第i行安装一架 激光枪的费用是Ri,在第i列安装的费用是Ci.要安装整个激光枪系统,总费用为这些 激光枪费用的乘积. 求杀死所有伞兵的最小费用. 构图: 把伞兵视为边,行与列视为顶点.增加源点和汇点,对于第i行,从源点向顶点i连接一条 容量为Ri的边.对于第j列,从顶点j向汇点连接一条容量为Rj的边. 如果某一点(i,j)有伞兵降落,则从顶点Ri向顶点

poj 3308 Paratroopers 最小割 最小点权覆盖

题目链接:http://poj.org/problem?id=3308 题意: 有一个M*N的图,上面的一些点上有伞兵. 可以设置一些枪在每行或者每列上,通过射击,这行或这列的伞兵就会被消灭.每个枪的设置有一个花费,如果设置多个枪,那么花费是设置每个枪的乘积. 问消灭所有伞兵最少的花费是多少. 思路: 每个点的伞兵至少要用那一列或者那一行设置的枪去消灭,那么就可以应用点覆盖的模型.把伞兵看成是一条边,这条边至少要用一个点来覆盖. 而题目中最终花费是所有花费的乘积,那么可以用对数log(x)+lo

POJ - 3308 Paratroopers(最大流)

1.这道题学了个单词,product 还有 乘积 的意思.. 题意就是在一个 m*n的矩阵中,放入L个敌军的伞兵,而我军要在伞兵落地的瞬间将其消灭.现在我军用一种激光枪组建一个防御系统,这种枪可以安装在一行(或者一列),并且安装在不同行(或者不同列)的费用是不一样的,枪的攻击范围是一行(或者一列).安装所有枪的费用是它们每个费用的“乘积”,现在求组建这个系统需要的最小费用. 2.与前面做的二分图的一道题有点相似(POJ - 3041 Asteroids(最小点覆盖数)).但是现在这道题在不同行(

POJ 3308 Paratroopers

Paratroopers Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 330864-bit integer IO format: %lld      Java class name: Main It is year 2500 A.D. and there is a terrible war between the forces of the Earth and

POJ 3308 最少点集覆盖

题意:和Uva 11419 类似. 首先最少点集覆盖 = 最大匹配. 我们可以在 S 和行 的边 不是1,有了权值,但是题意要求的是乘积最小,那么可以用 log(a*b) = loga + logb 转换,那么权值就是logr ,logc; 最大匹配 = 最大流(最大流一定经过最小割,最小割=最大流).那么题目就转换为求最大流了. 但是,这个题目很流氓,vector的邻接表超时,数组模拟的G++ WA,C++ AC. #include <cstdio> #include <cstring

poj 3308 Paratroopers(最小点权覆盖)

Paratroopers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8954   Accepted: 2702 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 infor

【POJ】【3308】Paratroopers

网络流/二分图最小点权覆盖 sigh……这题……TLE&RE了好几发 建一个二分图,左边的每个结点代表行,右边的代表列,如果在(i,j)这个位置有一个外星人,那么我们就连一条边 (左 i ->右 j),这样的话,求一个二分图最小点权覆盖即可. 为什么这样建图是对的?大家学过二分图应该知道点覆盖是啥吧……(至少学过最小点覆盖=最大匹配吧?)那么我们选了某一个点,比如我们选了左边的第 i 个点,这就表示我们在第 i 行建了一座激光炮,它能打到的外星人就是这个点连出去的所有边!也就是说对于每个外星