zoukankan      html  css  js  c++  java
  • 【POJ】【3308】Paratroopers

    网络流/二分图最小点权覆盖


      sigh……这题……TLE&RE了好几发

      建一个二分图,左边的每个结点代表行,右边的代表列,如果在(i,j)这个位置有一个外星人,那么我们就连一条边 (左 i ->右 j),这样的话,求一个二分图最小点权覆盖即可。

      为什么这样建图是对的?大家学过二分图应该知道点覆盖是啥吧……(至少学过最小点覆盖=最大匹配吧?)那么我们选了某一个点,比如我们选了左边的第 i 个点,这就表示我们在第 i 行建了一座激光炮,它能打到的外星人就是这个点连出去的所有边!也就是说对于每个外星人(每条边),它被打死(边被覆盖)当且仅当它所在行或列至少有一个方向有激光炮(它连接的两个端点至少有一个被选中),那么现在应该明白了吧= =我们就是要选出权值和最小的一组点,使得所有边都被覆盖。这个用网络流来做比较方便……(其实是我不会别的做法……)

      那么我们现在知道了这是一个二分图的模型,那么怎么建网络流的图呢?对于每个左边的顶点,我们连s->i,w=r[i],右边顶点连汇点t,边权(流量)同理。然后对于二分图中的边我们连(左->右,流量为INF),跑一个最大流(最小割)。(割掉某条边就表示选这个点,边权为INF表示不割它)

      看到这里你可能会问,这样做是不对的吧?样例都过不了的……

      其实……一开始我由于英语没学好……“product”的意思是乘积!!!也就是所有建造的激光炮的权值之积……sigh

      辣么怎么算积的最大值呢?网络流不是只能算和的最大值吗?下面就是见证奇迹的时刻:对所有的权值取log,然后对最终答案取exp!这样就华丽丽地将求乘积最大转化为了求和最大。

      

    Trick:这题是取了log的边权……所以在用Dinic增广的时候边界判定需要小心小心再小心。对于double类型的最大流我参考网上的代码重新写了一个模板……

    之前在【当前结点是否无法再继续增广(dfs时)】这个地方蛋疼了好久……因为边界处理的不好各种TLE

    然后是边集开小了……500×2的RE,500×3的AC……

      1 Source Code
      2 Problem: 3308        User: sdfzyhy
      3 Memory: 760K        Time: 0MS
      4 Language: G++        Result: Accepted
      5 
      6     Source Code
      7 
      8     //POJ 3308
      9     #include<cmath>
     10     #include<queue>
     11     #include<vector>
     12     #include<cstdio>
     13     #include<cstring>
     14     #include<cstdlib>
     15     #include<iostream>
     16     #include<algorithm>
     17     #define rep(i,n) for(int i=0;i<n;++i)
     18     #define F(i,j,n) for(int i=j;i<=n;++i)
     19     #define D(i,j,n) for(int i=j;i>=n;--i)
     20     #define pb push_back
     21     using namespace std;
     22     inline int getint(){
     23         int v=0,sign=1; char ch=getchar();
     24         while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     25         while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     26         return v*sign;
     27     }
     28     const int N=110,M=510,INF=1000000;
     29     const double eps=1e-8;
     30     typedef long long LL;
     31     /******************tamplate*********************/
     32 
     33     int n,m,l;
     34     double r[N],c[N];
     35     struct edge{
     36         int from,to;
     37         double cap,flow;
     38     };
     39     struct Net{
     40         edge E[M*3];
     41         int head[N],next[M*3],cnt;
     42         int Q[N];
     43         int s,t,d[N],cur[N];
     44         inline void add(int from,int to,double cap){
     45             E[++cnt]=(edge){from,to,cap,0};
     46             next[cnt]=head[from];
     47             head[from]=cnt;
     48             E[++cnt]=(edge){to,from,0,0};
     49             next[cnt]=head[to];
     50             head[to]=cnt;
     51         }
     52         inline void init(){
     53             cnt=1;
     54             n=getint();m=getint();l=getint();
     55             s=0; t=n+m+1;
     56             F(i,s,t) head[i]=0;
     57             F(i,1,n){
     58                 scanf("%lf",&r[i]);
     59                 add(s,i,log(r[i]));
     60             }
     61             F(i,1,m){
     62                 scanf("%lf",&c[i]);
     63                 add(i+n,t,log(c[i]));
     64             }
     65             int x,y;
     66             F(i,1,l){
     67                 x=getint(); y=getint();
     68                 add(x,y+n,INF);
     69             }
     70         }
     71         bool mklevel(){
     72             memset(d,-1,sizeof d);
     73             d[s]=0;
     74             int l=0,r=-1;
     75             Q[++r]=s;
     76             while(l<=r){
     77                 int x=Q[l++];
     78                 for(int i=head[x];i;i=next[i]){
     79                     edge&e=E[i];
     80                     if (d[e.to]==-1 && e.cap>e.flow){
     81                         d[e.to]=d[x]+1;
     82                         Q[++r]=(e.to);
     83                     }
     84                 }
     85             }
     86             return d[t]!=-1;
     87         }
     88         double dfs(int x,double a){
     89             if (x==t) return a;
     90             double flow=0;
     91             for(int &i=cur[x];i && flow<a;i=next[i]){
     92                 edge&e=E[i];
     93                 if (e.cap-e.flow>0 && d[e.to]==d[x]+1){
     94                     double f=dfs(e.to,min(a-flow,e.cap-e.flow));
     95                     flow+=f;
     96                     e.flow+=f;
     97                     E[i^1].flow-=f;
     98                 }
     99             }
    100             if (!flow) d[x]=-2;
    101             return flow;
    102         }
    103         double Dinic(){
    104             double flow=0;
    105             while(mklevel()){
    106                 F(i,s,t) cur[i]=head[i];
    107                 flow+=dfs(s,INF);
    108             }
    109             return flow;
    110         }
    111     }G1;
    112 
    113     int main(){
    114     #ifndef ONLINE_JUDGE
    115         freopen("3308.in","r",stdin);
    116         freopen("3308.out","w",stdout);
    117     #endif
    118         int T=getint();
    119         while(T--){
    120             G1.init();
    121             printf("%.4f
    ",exp(G1.Dinic()));
    122         }
    123         return 0;
    124     }
    View Code
  • 相关阅读:
    JAVA EE 第一阶段项目问题
    车辆管理系统之开始自己的任务(三)
    车辆管理系统之搭建框架 添加必要的数据 安装svn(二)
    车辆管理系统之分析信息建表(一)
    牛客问题
    记录---base64
    JAVA EE 第一阶段考试
    简单ssh框架整合
    Struts2拦截器
    Struts2文件上传
  • 原文地址:https://www.cnblogs.com/Tunix/p/4334725.html
Copyright © 2011-2022 走看看