Gym 101128F Sheldon Numbers(网络流)

【题目链接】 http://codeforces.com/gym/101128/attachments

【题目大意】

  给出一张地图,分为高地和低地,高低地的交界线上划有红线,
  现在要开小车跨过每条红线,当改变小车开的地形的时候,比如从高地开往低地,
  就需要多耗油A单位,也可以花B的耗油量抬高地形或者降低地形,
  问跨越所有红线所用的最少耗油量

【题解】

  我们发现对于每条红线,我们需要花A去跨越地形或者花B去抬高或者降低地形,
  所以我们将不同地形划分为两个集合,构成二分图,
  红线左右块连流量为A的边,汇点连高地,流量为B,源点连低地,流量为B,
  那么源汇的最小割就是征服这些红线需要的最小代价,求源汇最大流即可。

【代码】

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAX_V=3000;
struct edge{int to,cap,rev;};
vector<edge> G[MAX_V];
int level[MAX_V],iter[MAX_V];
void add_edge(int from,int to,int cap){
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s){
    memset(level,-1,sizeof(level));
    queue<int> que;
    level[s]=0;
    que.push(s);
    while(!que.empty()){
        int v=que.front(); que.pop();
        for(int i=0;i<G[v].size();i++){
            edge &e=G[v][i];
            if(e.cap>0&&level[e.to]<0){
                level[e.to]=level[v]+1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f){
    if(v==t)return f;
    for(int &i=iter[v];i<G[v].size();i++){
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to]){
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0){
                e.cap-=d;
                G[e.to][e.rev].cap+=d;
                return d;
            }
        }
    }return 0;
}
int max_flow(int s,int t){
    int flow=0;
    for(;;){
        bfs(s);
        if(level[t]<0)return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0){
            flow+=f;
        }
    }
}
const int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
int n,m,A,B;
char mp[55][55];
bool check(int x,int y){return (x>=0&&y>=0&&x<n&&y<m);}
void solve(){
    int s=n*m,t=s+1;
    for(int i=0;i<=t;i++)G[i].clear();
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(mp[i][j]==‘.‘)add_edge(s,i*m+j,B);
            else add_edge(i*m+j,t,B);
            for(int k=0;k<4;k++){
                int x=i+dx[k],y=j+dy[k];
                if(check(x,y))add_edge(i*m+j,x*m+y,A);
            }
        }
    }printf("%d\n",max_flow(s,t));
}
int main(){
    while(~scanf("%d%d%d%d",&n,&m,&A,&B)){
        for(int i=0;i<n;i++)scanf("%s",mp[i]);
        solve();
    }return 0;
}
时间: 2024-08-06 20:08:13

Gym 101128F Sheldon Numbers(网络流)的相关文章

UVALive-7279 - Sheldon Numbers【暴力】

UVALive-7279 - Sheldon Numbers 题目链接:7279 题目大意:给出[a,b],问在这个范围内的十进制数字,转化为二进制之后,形式满足ABAB-AB或者ABAB-A的有几个.(A表示连续的1,B表示连续的0) 第一种形式A的个数 > 0,B的个数 > 0. 第二种形式A的个数>0,B的个数可以等于0 题目思路:暴力出所有满足情况的数字,然后二分查找大于等于a,b的数字的下标.代码细节需要注意很多. 以下是代码: #include <bits/stdc++

Gym - 100203I I WIN 网络流

Gym - 100203I  I WIN 题意:一个n*m的矩阵包含W,I,N三种字符,问相邻的字符最多能组成不重叠的WIN. 思路:比赛的时候没有发现是网络流,,居然一度以为是二分图匹配,,写了一下没过就没改了,,知道了是网络流就好办了.设一个起点一个终点,起点和每个W之间连一条边,N和终点间连一条边,W和I之间连一条边,I和N之间连一条边,不过这里为了避免重复使用同一个I,应改成W到I连一条边,I连一条边到I',再从I'连一条边到N就可以保证最优解了.求一遍最大流即可. 1 #include

【枚举约数】Gym - 101412A - Ginkgo Numbers

给你一堆定义,问你在那个定义下,<p,q>是不是素数.其实那堆定义都不用管,只要看最下面给你的提示即可. 根据,只要把m^2+n^2当一个整体,去枚举(p^2+q^2)的约数即可,然后再枚举m, 这样的枚举出来是必要的,然后再根据这个充要条件判一下即可. #include<cstdio> #include<cmath> using namespace std; const double EPS=0.00000001; int T; int p,q; bool check

【最小割】【Dinic】Gym - 101128F - Landscaping

http://blog.csdn.net/lxy767087094/article/details/68942422 #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int dx[]={0,-1,0,1},dy[]={-1,0,1,0}; typedef long long ll; const ll INF=10

Gym - 100338E Numbers 贪心

Gym - 100338E 题意:给你n,k问在1-n中能整出k的字典序最小的数.范围1018 思路:比较简单的贪心了,枚举10的幂m,然后加上k-m%k, 更新答案就可以了,数据一定要用unsigned long long,我就在这里挂了几次,查了半天. 1 #include <iostream> 2 #include <cstdio> 3 #include <fstream> 4 #include <algorithm> 5 #include <c

Gym 101102J---Divisible Numbers(反推技巧题)

题目链接 http://codeforces.com/gym/101102/problem/J Description standard input/output You are given an array A of integers of size N, and Q queries. For each query, you will be given a set of distinct integers S and two integers L and R that represent a

codeforces Gym 100338E Numbers

题目:http://codeforces.com/gym/100338/attachments 贪心,每次枚举10的i次幂,除k后取余数r在用k-r补在10的幂上作为候选答案. #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxbit = 19; ull base[maxbit], n, k; void preDeal() { base[0] = 1; for(in

Codeforces Gym 100203I I - I WIN 网络流最大流

I - I WINTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87954#problem/I Description Given an n × m rectangular tile with each square marked with one of the letters W, I, and N, find the maximal numb

codeforces gym 100357 J (网络流)

题目大意 有n种物品,m种建筑,p个人. n,m,p∈[1,20] 每种建筑需要若干个若干种物品来建造.每个人打算建造一种建筑,拥有一些物品. 主角需要通过交易来建造自己的建筑,交易的前提是对方用多余的物品来换取自己需要的物品. 询问主角是否能建造成功自己的建筑,并给出方案. 解题分析 超级恶心的读入,而且有一组数据的给出方式里没有逗号,和样例所示不同= = 根据py的性质很容易想到用网络流来做.将每种物品拆成x,y两份. 若主角多了a物品b件,连一条S到物品a,x部流量为b的边. 若主角少了a