• 【费用流】BZOJ1927-[Sdoi2010]星际竞速


    【题目大意】

    有一些点,它们之间存在一些有向边(由编号小的到编号大的),从一点到另一点消耗时间为边长。也可以消耗Ti时间直接抵达任意一个点。问所有点都走一遍最少需要多少时间?

    【思路】

    ①将每个点i拆为i和i’。

    ②由S向i连(cap=1,cost=0)的边。由i'向T连(1,0)的边,表示抵达过该点。

    ③由S向i'连(1,Ti)的边,表示直接从某点跳转到i点。

    ④根据有向边[i,j]连(i,j')的边。

    为什么这样是正确的?由于我们只关心每个点都被抵达过而不关心路径。费用流的前提是最大流,我们一定可以保证所有点都被经过,那么就可以通过③④区分是用跳转抵达还是通过有向边抵达了。

    *好久不写费用流,华丽写挂一发。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<vector>
      6 #include<queue>
      7 #define S 0
      8 #define T 2*n+1
      9 using namespace std;
     10 const int INF=0x7fffffff;
     11 const int MAXN=(800+50)*2+1;
     12 struct node
     13 {
     14     int to,pos,cap,cost;
     15 };
     16 int n,m;
     17 vector<node> E[MAXN];
     18 int pre[MAXN],preedge[MAXN];
     19 
     20 void addedge(int u,int v,int w,int cos)
     21 {
     22     E[u].push_back((node){v,E[v].size(),w,cos});
     23     E[v].push_back((node){u,E[u].size()-1,0,-cos});
     24 }
     25 
     26 void init()
     27 {
     28     scanf("%d%d",&n,&m);
     29     for (int i=1;i<=n;i++)
     30     {
     31         int ai;
     32         scanf("%d",&ai);
     33         addedge(S,i+n,1,ai);
     34         addedge(S,i,1,0);
     35         addedge(i+n,T,1,0);
     36     }
     37     for (int i=0;i<m;i++)
     38     {
     39         int ui,vi,wi;
     40         scanf("%d%d%d",&ui,&vi,&wi);
     41         if (ui>vi) swap(ui,vi);
     42         addedge(ui,vi+n,1,wi);
     43     }
     44 }
     45 
     46 int spfa()
     47 {
     48     queue<int> que;
     49     int vis[MAXN],in[MAXN],dis[MAXN];
     50     memset(in,0,sizeof(in));
     51     memset(pre,-1,sizeof(pre));
     52     for (int i=S;i<=T;i++) dis[i]=INF;
     53     que.push(S);
     54     vis[S]=1;
     55     dis[S]=0;
     56     while (!que.empty())
     57     {
     58         int head=que.front();que.pop();
     59         vis[head]=0;
     60         for (int i=0;i<E[head].size();i++)
     61         {
     62             node &tmp=E[head][i];
     63             if (tmp.cap>0 && dis[tmp.to]>dis[head]+tmp.cost)
     64             {
     65                 dis[tmp.to]=dis[head]+tmp.cost;
     66                 pre[tmp.to]=head;
     67                 preedge[tmp.to]=i;
     68                 if (!in[tmp.to])
     69                 {
     70                     que.push(tmp.to);
     71                     in[tmp.to]=0;
     72                 }
     73             }
     74         }
     75     }
     76     if (dis[T]==INF) return 0;else return 1;
     77     //和dinic不同,不能再tmp.to==T时直接返回,因为要找到最短路 
     78 } 
     79 
     80 void mcf()
     81 {
     82     int ans=0;
     83     while (spfa())
     84     {
     85         int flow=INF; 
     86         for (int i=T;pre[i]!=-1;i=pre[i])
     87         {
     88             flow=min(flow,E[pre[i]][preedge[i]].cap);
     89         }
     90         for (int i=T;pre[i]!=-1;i=pre[i])
     91         {
     92             node& tmp=E[pre[i]][preedge[i]];
     93             tmp.cap-=flow;
     94             E[tmp.to][tmp.pos].cap+=flow;
     95             ans+=flow*tmp.cost;
     96         }
     97     }
     98     printf("%d",ans);
     99 }
    100 
    101 int main()
    102 {
    103     init();
    104     mcf();
    105 }
  • 相关阅读:
    .net core3.1 使用log4日志
    windows 使用IIS 部署 .net core3.1
    EntityFramework 延时加载、事务、导航属性
    EntityFramework EF状态跟踪和各种查询
    EF查看SQL2种方式 和 映射
    Sql Server 逻辑文件 '' 不是数据库 '' 的一部分。请使用 RESTORE FILELISTONLY 来列出逻辑文件名。
    async和await
    线程异常处理和取消和线程锁
    Task和TaskFactory
    thread:线程等待,回调
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5770375.html
Copyright © 2020-2023  润新知