zoukankan      html  css  js  c++  java
  • 网络流24题

    1.餐巾计划问题

    这道题目算这些题目里比较难的题目,详细的说一下

    首先我们注意到每天要求的纸巾不同,那很显然最后流入汇点一定是分别流入的

    考虑拆点

    按照一般的思路我们从超级源向早上连边表示提供新的纸巾

    接下来晚上流入汇点是否可以呢

    我们考虑一下我们晚上是要有向某一天的早上(快洗慢洗)连边的操作的

    这会导致进入汇点的流量不对

    所以我们改变一下

    早上向汇点连边,表示当天获得了xx条新纸巾

    而源点向晚上连边,表示可以获得xx条旧纸巾

    网上的题解写的是前一天晚上向下一天晚上连边,然后源点向每天早上连边

    其实我们可以每天早上向下一天早上连边,然后从起点向1早上连INF,这样可以减少边数

    另外晚上向慢洗快洗好的那天连边

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define rint register ll
    #define IL inline
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    const ll N=5000;
    const ll N2=N*20;
    const ll INF=1e9;
    bool inq[N];
    ll head[N],d[N],p[N],aa[N],n,m,s,t,l,f[N];
    struct re{
      ll a,b,c,flow,cost,from;
    }a[N2];
    void arr(ll x,ll y,ll z,ll cost)
    {
      a[++l].a=head[x];
      a[l].b=y;
      a[l].c=z;
      a[l].cost=cost;
      a[l].from=x;
      head[x]=l;
    }
    ll flow,cost;
    struct Dinic{
      ll n;
      bool bf()
      {
        rep(i,1,n) d[i]=INF;
        me(inq); p[s]=0; aa[s]=INF;
        queue<ll> q;
        q.push(s);
        while (!q.empty())
        {
          ll x=q.front(); q.pop(); inq[x]=0;
        for (rint u=head[x];u;u=a[u].a)
        {
          ll v=a[u].b;
          if (a[u].c>a[u].flow&&d[v]>d[x]+a[u].cost)
          {
            d[v]=d[x]+a[u].cost;
            p[v]=u;
            aa[v]=min(aa[x],a[u].c-a[u].flow);
            if (!inq[v])
            {
              q.push(v); inq[v]=1; 
            }
          }
        }
        }
        if (d[t]==INF) return(0);
        flow+=aa[t];
        cost+=d[t]*aa[t];
        ll x=t;
        while (x!=s)
        {
          ll u=p[x];
          a[u].flow+=aa[t];
          if (u%2) a[u+1].flow-=aa[t]; else a[u-1].flow-=aa[t];
          x=a[u].from;
        }
        return 1;
      }
      void mincost()
      {
        while (bf());
      }
    }D;
    ll pp,ff,nn,ss;
    IL void arr2(ll x,ll y,ll z,ll cost)
    {
      arr(x,y,z,cost);
      arr(y,x,0,-cost);
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      ios::sync_with_stdio(false);
      cin>>n;
      rep(i,1,n) cin>>f[i];
      s=0; t=2*n+1;
      cin>>pp>>m>>ff>>nn>>ss;
      arr2(s,1,INF,pp);
      rep(i,1,n)
      {
        arr2(i,t,f[i],0);
        if (i!=n) arr2(i,i+1,INF,0);
        arr2(s,i+n,f[i],0);
        if (i+nn<=n) arr2(i+n,i+nn,INF,ss);
        if (i+m<=n) arr2(i+n,i+m,INF,ff);
      }
      D.n=n*2+1;
      D.mincost();
      cout<<cost<<endl;
      return 0;
    }

    2. [CTSC1999]家园

    分层图跑最大流,还是比较简单的

    3. 飞行员配对方案问题

    裸题

    4.软件补丁问题

    并不是网络流的题目

    状压dp,由于转移存在环跑spfa

    5.太空飞行计划问题

    最小割裸题

    6.试题库问题

    裸题

    7. 最小路径覆盖问题

    二分图经典题目,前面的整理提到过了

    将每个点拆成入点和出点,跑最大流

    答案=点数-最大流

    8.魔术球问题

    这道题还是要写一下的

    首先从小到大枚举a和第二题是一样的,这样子的效率是高于二分答案的

    然后问题就变成了最小路径覆盖

    当最小路径覆盖大于它的时候,答案就是a-1

    然后输出路径的时候

    我们可以直接利用当前图,因为第n+1个一定没有在前面的环中放上

    然后我们查找到每个点的后一个点是什么

    注意多个环的话终点是t,一个环的话没有被更新终点是0

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    #define me(x) memset(x,0,sizeof(x))
    const int N=2e4;
    const int N2=1e5;
    const int INF=1e9;
    int s,t,n,m,flow,l,nxt[N];
    bool f[N];
    struct re{
        int a,b,c,flow,x1,y1;
    }a[N2];
    struct Di{
      bool vis[N];
      int head[N],d[N];
      void arr(int x,int y,int z,int x1,int y1)
      {
        a[++l].a=head[x];
        a[l].b=y;
        a[l].c=z;
        a[l].x1=x1;
        a[l].y1=y1;
        head[x]=l;
      }
      bool bfs()
      {
        me(vis);
        queue<int> q;
        q.push(s); d[s]=0; vis[s]=1;
        while(!q.empty())
        {
          rint x=q.front(); q.pop();
          for (rint u=head[x];u;u=a[u].a)
          {
            rint v=a[u].b;
            if (!vis[v]&&a[u].c>a[u].flow)
            {
              vis[v]=1; q.push(v); 
              d[v]=d[x]+1;
            }
          }
        }
        return(vis[t]);
      }
      int dfs(int x,int y)
      {
        if (x==t||!y) return(y);
        int ans=0,f;
        for (rint u=head[x];u;u=a[u].a)
        {
          rint v=a[u].b;
          if (d[v]==d[x]+1&&(f=dfs(v,min(a[u].c-a[u].flow,y)))>0)
          {
            ans+=f;
            a[u].flow+=f;
            if (u%2) a[u+1].flow-=f; else a[u-1].flow-=f;
            y-=f;
            if (!y) break;
          }
        }
        return(ans);
      }
      void maxflow()
      {
        while(bfs()) 
          flow+=dfs(s,INF);
      }
    }D;
    #define arr2(x,y,z,a,b) D.arr(x,y,z,a,b),D.arr(y,x,0,b,a)
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      ios::sync_with_stdio(false);
      s=0; t=10000;
      cin>>n;
      rep(i,1,10000)
      {
        int x1=i*2-1,x2=i*2;
        arr2(s,x1,1,s,i); arr2(x2,t,1,i,t);
        rep(j,1,i-1)
        {
          int tmp=sqrt(i+j);
          if (tmp*tmp==i+j)
          { 
            arr2(j*2-1,x2,1,j,i);
          }
        }
        D.maxflow();
        if (i-flow>n)
        {
          rep(i,1,l)
          if (a[i].c==a[i].flow&&a[i].c) 
          {
            nxt[a[i].x1]=a[i].y1;
            int k1;
            k1++;
          }
          cout<<i-1<<endl;
          rep(j,1,i-1)
          {
            int tt=j;
            if (!f[j])
            {
              while (j!=t&&j)
              {
                f[j]=1; 
                cout<<j<<" ";
                j=nxt[j]; 
              }
              cout<<endl;
            }
            j=tt;
          }
          exit(0);
        }
      }
      return 0;
    }

    9.最长不下降子序列问题

    10.航空路线问题

    网络流的话是裸题,两个路径求最大经过点数,显然费用流

    同时是dp经典题目

    有向无环图两条并行路径dp

    dp[i][j]转移的时候只能向max(i,j)转移

    为什么呢 因为这样既可以保证每个可行状态都可到达

    又能保证每个只会被算一次

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    #define IL inline
    #define rep(i,h,t) for (rint i=h;i<=t;i++)
    #define dep(i,t,h) for (rint i=t;i>=h;i--)
    map<string,int> M1;
    map<int,string> M2;
    string s,s1,s2;
    int n,m;
    const int N=105;
    int f[N][N],dp[N][N],jl1[N],jl2[N];
    struct re{
      int a,b;
    }pre[N][N];
    IL void maxa(int x,int y,int k,int a1,int b1)
    {
      if (dp[x][y]<k)
      {
        dp[x][y]=k; 
        pre[x][y].a=a1; pre[x][y].b=b1;
      }
    }
    int main()
    {
      freopen("1.in","r",stdin);
      freopen("1.out","w",stdout);
      ios::sync_with_stdio(false);
      cin>>n>>m;
      rep(i,1,n)
      {
        cin>>s; 
        M1[s]=i; M2[i]=s;
      }
      rep(i,1,m)
      {
        cin>>s1>>s2;
        int x1=M1[s1],x2=M1[s2];
        if (x1>x2) swap(x1,x2);
        f[x1][x2]=1;
      }
      #define pd(x,y) ((x!=y)||(x==n))
      dp[1][1]=1;
      rep(i,1,n)
        rep(j,1,n)
          if (dp[i][j])
          {
            int tmp=dp[i][j]+1;
            rep(k,min(max(i,j)+1,n),n)
            {
              if (f[i][k]) maxa(k,j,tmp,i,j);
              if (f[j][k]) maxa(i,k,tmp,i,j);
            }
          }
      if (dp[n][n])
      {
      cout<<dp[n][n]-1<<endl;
      int now1=n,now2=n,cnt1=0,cnt2=0;
      while (!(now1==1&&now2==1))
      {
        if (pre[now1][now2].a!=now1)
        {
          jl1[++cnt1]=pre[now1][now2].a;
          now1=pre[now1][now2].a;
        } else
        {
          jl2[++cnt2]=pre[now1][now2].b;
          now2=pre[now1][now2].b;
        }
      }
      dep(i,cnt1,1) cout<<M2[jl1[i]]<<endl;
      cout<<M2[n]<<endl;
      rep(i,1,cnt2) cout<<M2[jl2[i]]<<endl;
    } else cout<<"No Solution!"<<endl;
      return 0;
    }

    11.方格取数问题

    裸题,可以发现网格图是个二分图,按照行号+列号的奇偶性来判断就行了

    12.机器人路径规划问题(应该是题目有问题,如果起点是叶子节点就可以直接网络流了)

    13.圆桌问题

    14.骑士共存问题

    15.火星探险问题

    16.最长k可重线段集问题(ok 前面篇写过了)

    17.最长k可重区间集问题(ok前面篇写过了

    18.汽车加油行驶问题

    19.孤岛营救问题

    20.深海机器人问题

    21.数字梯形问题

    22.分配问题

    23.运输问题

    24.负载平衡问题

  • 相关阅读:
    数据库练习题
    支付类项目
    crm项目整理
    React 生成二维码
    Charles抓页面配置mac端
    Python之列表生成式、生成器、可迭代对象与迭代器
    01 Django基础
    12 jQuery的ajax
    11 事件委托(事件代理)
    10 jQuery的事件绑定和解绑
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/9481476.html
Copyright © 2011-2022 走看看