POJ3308 Paratroopers(最小割/最小点权覆盖)

把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖。

此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运算,最后再还原。

另外还可以从最小割的思路去这么理解:

每一行与源点相连,容量为该行的花费;每一列与汇点相连,容量为该列的花费;对于每个入侵者的坐标,该行该列连接一条容量INF的边。

要让源点汇点不连通,割边集必然与所有入侵者的行或列相关,而这样建模后的最小割就是最小的花费(容量INF的边必然不是最小割的一部分,其余的必然会选择某行或某列)。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 #define INF (1<<30)
  8 #define MAXN 111
  9 #define MAXM 1111
 10
 11 struct Edge{
 12     int v,cap,flow,next;
 13 }edge[MAXM];
 14 int vs,vt,NE,NV;
 15 int head[MAXN];
 16
 17 void addEdge(int u,int v,int cap){
 18     edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
 19     edge[NE].next=head[u]; head[u]=NE++;
 20     edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
 21     edge[NE].next=head[v]; head[v]=NE++;
 22 }
 23
 24 int level[MAXN];
 25 int gap[MAXN];
 26 void bfs(){
 27     memset(level,-1,sizeof(level));
 28     memset(gap,0,sizeof(gap));
 29     level[vt]=0;
 30     gap[level[vt]]++;
 31     queue<int> que;
 32     que.push(vt);
 33     while(!que.empty()){
 34         int u=que.front(); que.pop();
 35         for(int i=head[u]; i!=-1; i=edge[i].next){
 36             int v=edge[i].v;
 37             if(level[v]!=-1) continue;
 38             level[v]=level[u]+1;
 39             gap[level[v]]++;
 40             que.push(v);
 41         }
 42     }
 43 }
 44
 45 int pre[MAXN];
 46 int cur[MAXN];
 47 int ISAP(){
 48     bfs();
 49     memset(pre,-1,sizeof(pre));
 50     memcpy(cur,head,sizeof(head));
 51     int u=pre[vs]=vs,flow=0,aug=INF;
 52     gap[0]=NV;
 53     while(level[vs]<NV){
 54         bool flag=false;
 55         for(int &i=cur[u]; i!=-1; i=edge[i].next){
 56             int v=edge[i].v;
 57             if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
 58                 flag=true;
 59                 pre[v]=u;
 60                 u=v;
 61                 //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
 62                 aug=min(aug,edge[i].cap-edge[i].flow);
 63                 if(v==vt){
 64                     flow+=aug;
 65                     for(u=pre[v]; v!=vs; v=u,u=pre[u]){
 66                         edge[cur[u]].flow+=aug;
 67                         edge[cur[u]^1].flow-=aug;
 68                     }
 69                     //aug=-1;
 70                     aug=INF;
 71                 }
 72                 break;
 73             }
 74         }
 75         if(flag) continue;
 76         int minlevel=NV;
 77         for(int i=head[u]; i!=-1; i=edge[i].next){
 78             int v=edge[i].v;
 79             if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
 80                 minlevel=level[v];
 81                 cur[u]=i;
 82             }
 83         }
 84         if(--gap[level[u]]==0) break;
 85         level[u]=minlevel+1;
 86         gap[level[u]]++;
 87         u=pre[u];
 88     }
 89     return flow;
 90 }
 91 int main(){
 92     double f;
 93     int t,n,m,l,a,b;
 94     scanf("%d",&t);
 95     while(t--){
 96         scanf("%d%d%d",&n,&m,&l);
 97         vs=0; vt=n+m+1; NV=vt+1; NE=0;
 98         memset(head,-1,sizeof(head));
 99         for(int i=1; i<=n; ++i){
100             scanf("%f",&f);
101             addEdge(vs,i,log10(f));
102         }
103         for(int i=1; i<=m; ++i){
104             scanf("%f",&f);
105             addEdge(i+n,vt,log10(f));
106         }
107         while(l--){
108             scanf("%d%d",&a,&b);
109             addEdge(a,b+n,INF);
110         }
111         printf("%.4f\n",pow(10,ISAP()));
112     }
113     return 0;
114 }
时间: 2024-12-12 05:29:41

POJ3308 Paratroopers(最小割/最小点权覆盖)的相关文章

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

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

【BZOJ-2229】最小割 最小割树(最大流+分治)

2229: [Zjoi2011]最小割 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1565  Solved: 560[Submit][Status][Discuss] Description 小白在图论课上学到了一个新的概念——最小割,下课后小白在笔记本上写下了如下这段话: “对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割. 对于带权图来说,将所有顶点处在不同部分的边的

【BZOJ-4519】不同的最小割 最小割树(分治+最小割)

4519: [Cqoi2016]不同的最小割 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 393  Solved: 239[Submit][Status][Discuss] Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成 两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将 所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t

【BZOJ4519】[Cqoi2016]不同的最小割 最小割树

[BZOJ4519][Cqoi2016]不同的最小割 Description 学过图论的同学都知道最小割的概念:对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同一个部分中,则称这个划分是关于s,t的割.对于带权图来说,将所有顶点处在不同部分的边的权值相加所得到的值定义为这个割的容量,而s,t的最小割指的是在关于s,t的割中容量最小的割.而对冲刺NOI竞赛的选手而言,求带权图中两点的最小割已经不是什么难事了.我们可以把视野放宽,考虑有N个点的无向连通图中所有点对的最

bzoj2229: [Zjoi2011]最小割(分治最小割+最小割树思想)

2229: [Zjoi2011]最小割 题目:传送门 题解: 一道非常好的题目啊!!! 蒟蒻的想法:暴力枚举点对跑最小割记录...绝对爆炸啊.... 开始怀疑是不是题目骗人...难道根本不用网络流???一看路牌....分治最小割?最小割树? 然后开始各种%论文... 简单来说吧,根据各种本蒟蒻不会证明的理论,那么:所有最小割都不是完全独立的,总共有n-1种(也就是树上的n-1条边)最小割 恰好和树的定义一样啊! 那么用一个solve递归函数来解决,一开始任意找两个点作为st和ed来最小割,然后分

BZOJ 2229 ZJOI2011 最小割 最小割+分治 400AC达成&amp;&amp;2000Submission达成

题目大意:给定一个图,多次询问有多少个点对之间的最小割小于等于某个值 最小割分治- - 首先朴素的想法是做O(n^2)遍网络流 但是这样显然是过不去的 根据一些结论,最小割最多有n-1个,这n-1个最小割构成一个最小割树 别问我为什么- - 因此我们分治寻找这n-1个最小割 每层分治,先任选两个点作为源汇做一遍最小割 然后找出S集和T集,对所有S集的点和T集的点构成的点对用本次得到的最小割更新一遍 注意更新的是全部S集和全部T集,不只是本次分治内部的S集和T集 然后将本次分治的点分成S集和T集,

[ZJOI2011] 最小割 - 最小割树

最小割树裸题 建树后,以每个点为根跑DFS求出距离矩阵,然后暴力回答询问即可 #include <bits/stdc++.h> using namespace std; #define int long long const int maxn=6e2; const int maxm=4e4; const int inf=1e13; int n,m,q; //for the target graph vector <pair<int,int> > g[maxn]; voi

POJ 2125 --Destroying The Graph【最小割解决 &quot;最小点权覆盖问题&quot; &amp;&amp; 输出解(割边集) &amp;&amp; 各种不懂】

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7597   Accepted: 2434   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

hdu 3987 Harry Potter and the Forbidden Forest【网路流最小割模型】

Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1549    Accepted Submission(s): 528 Problem Description Harry Potter notices some Death Eaters try to slip