• BZOJ 1927 SDOI2010 星际竞速 最小费用最大流


      中文题面,还特长。请各位自行品尝→星际竞速

    分析:

      首先拆穿题面一个伪装。题面里竟然明摆着说是双向图,后来又变成了“只能由每个星球飞往引力比它大的星球”,所以这就是出题人凑字数的把戏,我们直接将其看作单向边就好了(不过如果给的顺序反了要swap一下)

      这个题目的图比较好建,比起那些奇奇怪怪的转化,我们只需要按着题面建图就好了。

      我们要满足“每个点恰好访问一次”这个限制,在求最小费用的题目里,我们应该用最大流来保证这种限制(就是说,当全图为最大流时,即为访问每个点恰好一次)

      我们按照在这个思路去建图。将每个星球拆成一个入点和一个出点

      从原点S向每个星球的入点连一条容量为1费用为0的边。

      从原点向每个点的出点连一条容量为1费用为瞬移定位时间的边(表示不走寻常路的流?)

      假如在原图中存在(x->y)的一条边,那么我们从x的入点向y的出点连容量为1费用为航路所需时间的边(表示从x点走向了y点完成了这条航道的使命?)

      最小费用最大流,输出费用,结束。

    代码:

     1 #include<bits/stdc++.h>
     2 #define ms(a,x) memset(a,x,sizeof(a))
     3 using namespace std;
     4 const int N=5000,M=100000;
     5 const int inf=0x3f3f3f3f;
     6 queue<int>q;int c1[N],c2[N],cnt;
     7 struct node{int y,z,f,nxt;}e[M];
     8 int lst[N],pre[N],S,T;bool vis[N];
     9 int h[N],c=1,n,m,d[N],f[N],ans,tot;
    10 void add(int x,int y,int l,int z){
    11     e[++c]=(node){y,z,l,h[x]};h[x]=c;
    12     e[++c]=(node){x,-z,0,h[y]};h[y]=c;
    13 } bool spfa(){
    14     for(int i=S;i<=T;i++) pre[i]=-1,
    15     f[i]=inf,lst[i]=vis[i]=0,d[i]=inf;
    16     q.push(S);d[S]=0;pre[S]=0;
    17     while(q.size()){
    18         int x=q.front();q.pop();vis[x]=0;
    19         for(int i=h[x],y;~i;i=e[i].nxt)
    20         if(d[y=e[i].y]>d[x]+e[i].z&&e[i].f){
    21             d[y]=d[x]+e[i].z;pre[y]=x;lst[y]=i;
    22             f[y]=min(f[x],e[i].f);
    23             if(!vis[y]) vis[y]=1,q.push(y);
    24         }
    25     } return (pre[T]!=-1);
    26 } void solve(){
    27     while(spfa()){
    28         ans+=d[T]*f[T];int x=T;
    29         while(x) e[lst[x]].f-=f[T],
    30         e[lst[x]^1].f+=f[T],x=pre[x];
    31     } return ;
    32 } int main(){ ms(h,-1);
    33     scanf("%d%d",&n,&m);S=0;cnt=0;
    34     for(int i=1;i<=n;i++) 
    35     c1[i]=++cnt,c2[i]=++cnt;T=++cnt;
    36     for(int i=1,x;i<=n;i++)
    37     scanf("%d",&x),add(S,c2[i],1,x);
    38     for(int i=1;i<=n;i++) add(S,c1[i],1,0);
    39     for(int i=1;i<=n;i++) add(c2[i],T,1,0);
    40     for(int i=1,x,y,z;i<=m;i++){
    41         scanf("%d%d%d",&x,&y,&z);if(x>y)
    42         swap(x,y);add(c1[x],c2[y],1,z);
    43     } solve();
    44     printf("%d
    ",ans);return 0;
    45 }
    费用流
  • 相关阅读:
    Python之 continue继续循环
    Python之 break退出循环
    Python之 while循环
    Python之 for循环
    java中collection、map、set、list简介 (转)
    CloudSim介绍和使用
    智能指针和动态内存
    boost signal2
    boost 信号 :
    boost库 线程使用
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10250294.html
Copyright © 2020-2023  润新知