• Gym101128F:Landscaping


    题意

    有一片h*w的草坪,要把每一行从左到右修剪一遍,每一列从上到下修剪一遍。每个草坪要么是高低要么是平地。割草机从高地到平地或者从平地到高地,需要花费a。也可以把平地变为高地或者把高地变为平地,花费为b。求出最小花费是多少。

    分析

    网络流,应该也不算网络流里的难题,建图还是比较好想的(虽然我不会)。

    当时在场上瞎几把建图,最后还是没过

    这场结束后问了一下二发学长,恍然大悟。

    把草地分为两个集合S和T,平地为S集合,高地位T集合,然后用最少的花费将两个集合分开,那么就是最小割了。

    从s(源点)向每个平地连一条容量为b的边,从每个高地向t(汇点)连一条容量为b的边。如果需要把平地变高地或者把高低变平地,就割这几条边就可以了。

    每个小草坪都向左边和下面的小草坪连双向边。为什么是双向边?因为是按照每个小草地的性质分为的两大集合。也可以理解为有可能从平地开始,也有可能从高地开始。

    然后跑dinic就可以惹~~

    下面是代码~

    其实没啥看的,建图很简单,dinic是网上的模板··雾

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <vector>
      6 #include <queue>
      7 using namespace std;
      8 
      9 #define N 5000
     10 #define INF 2147483000
     11 
     12 struct Edge
     13 {
     14     int from,to,cap,flow;
     15     Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
     16 };
     17 
     18 struct Dinic
     19 {
     20     int n,m,s,t;//结点数,边数(包括反向弧),源点编号,汇点编号
     21     vector<Edge>edges;//边表,dges[e]和dges[e^1]互为反向弧
     22     vector<int>G[N];//邻接表,G[i][j]表示结点i的第j条边在e数组中的编号
     23     bool vis[N]; //BFS的使用
     24     int d[N]; //从起点到i的距离
     25     int cur[N]; //当前弧下标
     26 
     27     void addedge(int from,int to,int cap)
     28     {
     29         edges.push_back(Edge(from,to,cap,0));
     30         edges.push_back(Edge(to,from,0,0));
     31         int  m=edges.size();
     32         G[from].push_back(m-2);
     33         G[to].push_back(m-1);
     34     }
     35 
     36     bool bfs()
     37     {
     38         memset(vis,0,sizeof(vis));
     39         queue<int>Q;
     40         Q.push(s);
     41         d[s]=0;
     42         vis[s]=1;
     43         while(!Q.empty())
     44         {
     45             int x=Q.front();Q.pop();
     46             for(int i=0;i<G[x].size();i++)
     47             {
     48                 Edge&e=edges[G[x][i]];
     49                 if(!vis[e.to]&&e.cap>e.flow)//只考虑残量网络中的弧
     50                 {
     51                     vis[e.to]=1;
     52                     d[e.to]=d[x]+1;
     53                     Q.push(e.to);
     54                 }
     55             }
     56 
     57         }
     58         return vis[t];
     59     }
     60 
     61     int dfs(int x,int a)//x表示当前结点,a表示目前为止的最小残量
     62     {
     63         if(x==t||a==0)return a;//a等于0时及时退出,此时相当于断路了
     64         int flow=0,f;
     65         for(int&i=cur[x];i<G[x].size();i++)//从上次考虑的弧开始,注意要使用引用,同时修改cur[x]
     66         {
     67             Edge&e=edges[G[x][i]];//e是一条边
     68             if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
     69             {
     70                 e.flow+=f;
     71                 edges[G[x][i]^1].flow-=f;
     72                 flow+=f;
     73                 a-=f;
     74                 if(!a)break;//a等于0及时退出,当a!=0,说明当前节点还存在另一个曾广路分支。
     75 
     76             }
     77         }
     78         return flow;
     79     }
     80 
     81     int Maxflow(int s,int t)//主过程
     82     {
     83         this->s=s,this->t=t;
     84         int flow=0;
     85         while(bfs())//不停地用bfs构造分层网络,然后用dfs沿着阻塞流增广
     86         {
     87             memset(cur,0,sizeof(cur));
     88             flow+=dfs(s,INF);
     89         }
     90         return flow;
     91     }
     92 }dinic;
     93 int h,w,a,b;
     94 char G[55][55];
     95 const int dx[]={0,0,1,-1};
     96 const int dy[]={1,-1,0,0};
     97 int main(){
     98     scanf("%d%d%d%d",&h,&w,&a,&b);
     99     dinic.s=0,dinic.t=h*w+1;
    100 
    101     for(int i=1;i<=h;i++){
    102         for(int j=1;j<=w;j++){
    103             scanf(" %c",&G[i][j]);
    104             if(G[i][j]=='.')
    105                 dinic.addedge(dinic.s,(i-1)*w+j,b);
    106             else
    107                 dinic.addedge((i-1)*w+j,dinic.t,b);
    108         }
    109     }
    110     for(int i=1;i<=h;i++){
    111         for(int j=1;j<=w;j++){
    112             int u=(i-1)*w+j;
    113             int v1=i*w+j;
    114             int v2=(i-1)*w+j+1;
    115             if(i<h){
    116                dinic.addedge(u,v1,a);dinic.addedge(v1,u,a);
    117             }
    118             if(j<w){
    119                dinic.addedge(u,v2,a);dinic.addedge(v2,u,a);
    120             }
    121         }
    122     }
    123     int ans=dinic.Maxflow(dinic.s,dinic.t);
    124     cout<<ans;
    125 return 0;
    126 }
    View Code
  • 相关阅读:
    CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第七节
    CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第六节
    数组逆序=全局内存版 VS 共享内存版
    CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第五节
    CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第四节
    【转载】Caffe + Ubuntu 14.04 + CUDA 6.5 新手安装配置指南
    Andrew NG 自动化所演讲(20140707):DeepLearning Overview and Trends
    机器学习资源
    CUDA实现数组倒序
    CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第三节
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/8783295.html
Copyright © 2020-2023  润新知