• POJ 3308(最小割最大流)


    题意:

    火星人侵略地球,他们意图登陆破坏某个地区的兵器工厂。据探子回报,火星人登陆的地区为n*m大小的地域,而且每一个火星人的着陆点坐标已知。

    火星人很强悍,只要有一个火星人着陆后能够幸存,他必定能毁坏这片区域的全部兵工厂。为了防止这种情况发生,必须保证在火星人着陆的一瞬间把他们全部同时杀死。

    现在防卫队有一个激光枪,开一枪就能把 在同一行(或同一列)着陆的火星人全部杀死。但是这种激光枪的使用是有代价的,把这种激光枪安装到不同行的行首、或者不同列的列首,费用都不同。现在已知把激光枪安装到任意位置的费用,总的花费为这些安装了激光枪的行列花费的乘积。

    问怎样安装激光枪才能在杀死所有火星人的前提下费用最少?

    题解:

    这个题是很裸的二分图的最小顶点覆盖,这种问题一般转化成网络流的最小割。

    这道题要求的是乘积,我们应该马上想到log取对数。(与之类似的题:HDU 3666,也是很经典的题)

    然后就是构图了:

    设S为超级源点,T为超级汇点

    S与每行连一条容量为log10(row[i])的点(row[i]是在i行建激光炮的花费)

    T与每列连一条容量为log10(col[i])的点(col[i]是在i列建激光炮的花费)

    对于每一个火星人降落的位置(x,y)连一条从x到y容量为INF的边,意味着这条表永远不会被割断

    图就建好了,跑最大流就行了!

    View Code
     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <cmath>
     6 #define N 201000
     7 #define M  2001000
     8 #define INF 100.0
     9 using namespace std;
    10 int head[N],next[M],to[M],cnt,S,T,n,m,num,layer[N],q[M<<4],tt;
    11 double len[M],row[N],col[N];
    12 inline void add(int u,int v,double w)
    13 {
    14     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
    15     to[cnt]=u; len[cnt]=0.0; next[cnt]=head[v]; head[v]=cnt++;
    16 }
    17 void read()
    18 {
    19     memset(head,-1,sizeof head);
    20     cnt=0;
    21     scanf("%d%d%d",&n,&m,&num);
    22     S=0; T=n+m+1;
    23     for(int i=1;i<=n;i++) scanf("%lf",&row[i]),add(S,i,log10(row[i]));
    24     for(int i=1;i<=m;i++) scanf("%lf",&col[i]),add(i+n,T,log10(col[i]));
    25     for(int i=1,a,b;i<=num;i++)
    26     {
    27         scanf("%d%d",&a,&b);
    28         add(a,b+n,INF);
    29     }
    30 }
    31 bool bfs()
    32 {
    33     memset(layer,-1,sizeof layer);
    34     int h=1,t=2,sta;
    35     q[1]=S; layer[S]=0;
    36     while(h<t)
    37     {
    38         sta=q[h++];
    39         for(int i=head[sta];~i;i=next[i])
    40             if(len[i]>0.0&&layer[to[i]]<0)
    41             {
    42                 layer[to[i]]=layer[sta]+1;
    43                 q[t++]=to[i];
    44             }
    45     }
    46     return layer[T]!=-1;
    47 }
    48 double min(double a,double b)
    49 {
    50     if(a<b) return a;
    51     else return b;
    52 }
    53 double find(int u,double cur_flow)
    54 {
    55     if(u==T) return cur_flow;
    56     double result=0.0,tmp;
    57     for(int i=head[u];~i&&result<cur_flow;i=next[i])
    58         if(len[i]>0.0&&layer[to[i]]==layer[u]+1)
    59         {
    60             tmp=find(to[i],min(len[i],cur_flow-result));
    61             len[i]-=tmp; len[i^1]+=tmp; result+=tmp;
    62         }
    63     if(result<=0.000001) layer[u]=-1;
    64     return result;
    65 }
    66 void dinic()
    67 {
    68     double ans=0.0;
    69     while(bfs()) ans+=find(S,INF);
    70     ans=pow(10,ans);
    71     printf("%.4lf\n",ans);
    72 }
    73 int main()
    74 {
    75     scanf("%d",&tt);
    76     while(tt--)
    77     {
    78         read();
    79         dinic();
    80     }
    81     system("pause");
    82     return 0;
    83 }

    附HDU 3666代码(差分约束系统)

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cmath> 
     6 #define N 2001
     7 #define M 400000
     8 using namespace std;
     9 int n,m,cnt,to[M],next[M],head[N],q[M<<3],num[N];
    10 double dis[N],len[M],l,u; 
    11 bool vis[N];
    12 void add(int u,int v,double w)
    13 {
    14     to[cnt]=v; len[cnt]=w; next[cnt]=head[u]; head[u]=cnt++;
    15 }
    16 void read()
    17 {
    18     memset(dis,0x7f,sizeof dis); 
    19     memset(head,0,sizeof head); 
    20     memset(vis,0,sizeof vis); 
    21     memset(num,0,sizeof num);
    22     cnt=1; 
    23     double ls; 
    24     l=log(l); u=log(u); 
    25     for(int i=1;i<=n;i++)
    26         for(int j=1;j<=m;j++)
    27         {
    28             scanf("%lf",&ls);
    29             ls=log(ls); 
    30             add(n+j,i,u-ls); 
    31             add(i,n+j,ls-l); 
    32         } 
    33 } 
    34 bool spfa()
    35 {
    36     int h=1,t=2;
    37     q[1]=1; vis[1]=true; dis[1]=0.0; num[1]=1; 
    38     while(h<t)
    39     {
    40         int sta=q[h++];
    41         vis[sta]=false;
    42         for(int i=head[sta];i;i=next[i])
    43         {
    44             if(dis[to[i]]>dis[sta]+len[i])
    45             {
    46                 dis[to[i]]=dis[sta]+len[i];
    47                 if(!vis[to[i]])
    48                 {
    49                     vis[to[i]]=true;
    50                     q[t++]=to[i];
    51                     num[to[i]]++; 
    52                     if(num[to[i]]>(int)(sqrt((double)(n+m)))) return false; 
    53                 } 
    54             }
    55         }
    56     }
    57     return true; 
    58 } 
    59 int main()
    60 {
    61     while(scanf("%d%d%lf%lf",&n,&m,&l,&u)!=EOF)
    62     {
    63         read();
    64         if(spfa()) printf("YES\n");
    65         else printf("NO\n"); 
    66     } 
    67     system("pause");
    68     return 0;
    69 }
    没有人能阻止我前进的步伐,除了我自己!
  • 相关阅读:
    集合中的3个经典练习题
    创建泛类集合List以及数组转集合,集合转数组的应用
    添加一个txt文件(例如在桌面),利用后台对文件写入内容
    File类的创建,删除文件
    集合中存放随机数的问题之解析
    集合中的类型转化 以及求集合中元素的最大值,平均值
    response.sendRedirect()使用注意事项
    request.getContextPath是为了解决相对路径的问题,可返回站点的根路径
    java中instanceof的用法
    getParameter 与 getAttribute的区别
  • 原文地址:https://www.cnblogs.com/proverbs/p/2659880.html
Copyright © 2020-2023  润新知