UVALive 5905 Pool Construction 最小割,s-t割性质 难度:3

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3916

这道题要求一种填充+挖坑+建屏障的方法,使得这块土地上的所有坑和草地之间都有屏障,挖坑花费d每块,填充花费f每块,建屏障花费b每两块之间,注意并不要求一定有坑,但是外围一圈要一定没有坑,所以需要预先填充好

令st代表平地,ed代表坑,边权为花费,那么本题是要求一个st-ed最小割,因为s到平地花费为0,所以不建边,同理坑到ed也不需要花费不建边,每个点到相邻点建边,容量为b,s到坑建边,容量为d,平地到e建边,容量为f,为了防止外围的平地被挖,容量设为inf.

以st为起点,ed为终点,求一遍最大流,即最小割即可
这道题一开始会以为是dp,其实是一道最小割,虽然有2500个点,50000条边左右,但是仍然可以用网络流跑过,一开始想不出怎么处理屏障,但是其实只需要把每个点和相邻点之间都连起来即可,横向的流量没有意义,也就是说只有平地和坑之间的边会限制流量.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=5000;
const int maxm=5000000;
const int inf=0x3fffffff;
int first[maxn];
struct edge{
        int nxt,from,t,f,c;
}e[maxm];
int w,h,d,fl,b,len;
char maz[60][60];
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
int st,ed,num;

int dis[maxn],gap[maxn];
bool in(int x,int y){return x>=0&&x<h&&y>=0&&y<w;}
void addedge(int from,int t,int c){
        e[len].nxt=first[from];
        e[len].from=from;
        e[len].t=t;
        e[len].f=c;
        e[len].c=c;
        first[from]=len++;
        swap(from,t);c=0;

        e[len].nxt=first[from];
        e[len].from=from;
        e[len].t=t;
        e[len].f=c;
        e[len].c=c;
        first[from]=len++;
}
int dfs(int s,int flow){
        if(s==ed)return flow;
        int mindis=num-1;
        int tflow=flow,sub;
        for(int p=first[s];p!=-1;p=e[p].nxt){
                int t=e[p].t;
                if(e[p].f>0){
                        if(dis[t]+1==dis[s]){
                                sub=dfs(t,min(tflow,e[p].f));
                                e[p].f-=sub;e[p^1].f+=sub;
                                tflow-=sub;
                                if(dis[st]>=ed)return flow-tflow;
                                if(tflow<=0)break;
                        }
                        mindis=min(mindis,dis[t]);
                }
        }
        if(flow-tflow<=0){
                --gap[dis[s]];
                if(gap[dis[s]]==0)dis[st]=ed;
                else {
                        dis[s]=mindis+1;
                        ++gap[dis[s]];
                }
        }
        return flow-tflow;
}

int maxflow(){
        int flow=0;
        gap[0]=num;
        while(dis[st]<ed){
                flow+=dfs(st,inf);
        }
        return flow;
}
void init(){
        len=0;
        st=w*h;
        ed=st+1;
        num=st+2;
        fill(first,first+num,-1);
        fill(gap,gap+num,0);
        fill(dis,dis+num,0);
}
int main(){
        int T;
        scanf("%d",&T);
        while(T--){
                scanf("%d%d%d%d%d",&w,&h,&d,&fl,&b);
                init();
                int ans=0;
                for(int i=0;i<h;i++)scanf("%s",maz[i]);

                for(int i=0;i<h;i++){
                        for(int j=0;j<w;j++){
                                for(int k=0;k<4;k++){
                                        int tx=i+dx[k],ty=j+dy[k];
                                        if(in(tx,ty)){
                                                addedge(i*w+j,tx*w+ty,b);
                                        }
                                }
                                if(maz[i][j]==‘#‘){
                                        if(i==0||i==h-1||j==0||j==w-1){
                                               addedge(i*w+j,ed,inf);
                                        }
                                        else {
                                                addedge(i*w+j,ed,d);
                                        }
                                }
                                else {
                                        if(i==0||i==h-1||j==0||j==w-1){
                                               ans+=fl;
                                                maz[i][j]=‘#‘;
                                               addedge(i*w+j,ed,inf);
                                        }
                                        else {
                                               addedge(st,i*w+j,fl);
                                        }
                                }
                        }
                }
                ans+=maxflow();
                printf("%d\n",ans);
        }
        return 0;
}

  

时间: 2024-12-25 10:41:28

UVALive 5905 Pool Construction 最小割,s-t割性质 难度:3的相关文章

Uva -1515 Pool construction(最小割)

输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 首先把最外一圈的洞变成草,并累加花费. 增加一个源点和一个汇点,源点连接每个草地,汇点连接每个洞. 源点与最外一圈的草地连一条容量无穷大的边,与其他草地连一条容量为d的边.表示把这条弧切断,割的容量增加d,草就会变成洞. 每个洞与汇点连一条容量为f的边. 相邻两个格子之间连一条双向边. 用最大流算法求最小割在加上之前把边界上的洞变成草的费用,就是最小花费. 用最小

UVa1515 Pool construction (最小割)

链接:http://vjudge.net/problem/UVA-1515 分析:首先分析一个特例,如果草地“#”和洞“.”不允许相互转化,那么我们可以直接从草地‘#”出发向图中相邻洞格子“.”连一条容量为b的弧,源点S向所有草地“#”连一条弧,所有洞“.”向汇点T连一条弧,容量均为无穷大,那么最小割就是建围栏的总费用. 这道题在上述基础上加了草地和洞可以相互转化这一条件.根据刚才的思路,我们可以联想到,只要草地“#”转化成洞“.”的时候,就不需要在它和周围的洞“.”之间建围栏了,那么我们可以限

训练指南 UVALive - 3126(DAG最小路径覆盖)

layout: post title: 训练指南 UVALive - 3126(DAG最小路径覆盖) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图 - 图论 - 训练指南 - 最小路径覆盖 Taxi Cab Scheme UVALive - 3126 题目大意:n个客人,从城市的不同位置出发,到达他们的目的地.已知每个人的出发时间hh:mm,出发地点(x1,y1)及目的地(x2,y2),要求使用最少的出租车接

UVa 1515 (最小割) Pool construction

题意: 输入一个字符矩阵,'.'代表洞,'#'代表草地.可以把草改成洞花费为d,或者把洞改成草花费为f,最后还要在草和洞之间修围栏花费为b. 但要保证最外一圈是草,求最小费用. 分析: 还不是特别理解紫书上的讲解.. 首先把最外一圈的洞变成草,并累加花费. 增加一个源点和一个汇点,源点连接每个草地,汇点连接每个洞. 源点与最外一圈的草地连一条容量无穷大的边,与其他草地连一条容量为d的边.表示把这条弧切断,割的容量增加d,草就会变成洞. 每个洞与汇点连一条容量为f的边. 相邻两个格子之间连一条双向

Uva1515 Pool construction

Time Limit: 3000MS64bit IO Format: %lld & %llu 网络流 最小割 心生绝望,用了好久的网络流模板居然是错的. ↑居然之前还侥幸能过一堆(并不)题. ______ 利用边容量来限制花费: 边缘的坑必须填上,每格花费为f: 如果一个地方id是坑,将其填上,从S到id连边,容量为f: 如果一个地方id是草,在这挖坑,从id到T连边,容量为d: 建立栅栏:每格向四周连边,容量为b: ↑如此建边起到了限制最小花费的作用,如果挖坑的代价比种草小,挖坑的边先流满,反

UVA 1515 Pool construction 水塘(最大流,经典)

题意:给一个h*w的矩阵,每个格子中是'#'和'.'两个符号之一,分别代表草和洞.现在要将洞给围起来(将草和洞分离),每条边需花费b元(即将一个洞包起来需要4边,将2个连续的洞包起来需要6边,省了2条边).有个特殊能力,能将洞变成草,花费f.当然也能将草变成洞,花费d.围起洞来需要多少花费.矩阵四周最边边的格子都必须是草,即出现洞就必须转草. 转换:洞--->草--->洞  f   d   元/格 围洞: b元/边. 分析:如果能够尽量让洞都靠在一起,那肯定是最小花费,因为少了很多条边.但是转

UVA - 10480 Sabotage 最小割,输出割法

UVA - 10480 Sabotage 题意:现在有n个城市,m条路,现在要把整个图分成2部分,编号1,2的城市分成在一部分中,拆开每条路都需要花费,现在问达成目标的花费最少要隔开那几条路. 题解:建图直接按给你的图建一下,然后呢跑一下最大流,我们就知道了最小割是多少,答案就是最小割了  . 现在要求输出割法.我们从s开始往前跑,如果某条正向边有流量,我们就按着这条边继续往外走,知道无法再走,把所有经历过的点都染一下色.最后看所有的边,是不是有一头是染色了,另一头没有染色,如果是,这条边就是割

[UVALive] 6492 Welcome Party(最小点覆盖)

6492 Welcome Party For many summers, the Agile Crystal Mining company ran an internship program for students. Theygreatly valued interns' ability to self-organize into teams. So as a get-to-know-you activity duringorientation, they asked the interns

XTU 1261 - Roads - [最小割][2017年湘潭邀请赛(江苏省赛)B题]

之前在网上搜了一个下午没搜到这道题的题解,然后同时又对着叉姐写的两行字题解看了一个下午: 虽然基本上已经知道了这题的思路,但愣是因为自己代码实现起来太繁复,外加不确定正确性,没敢码-- 但是一道题肝了一下午没肝出来,就要放弃的话,怕是太扎心了,忍不住就跑去ICPCCamp.Post问叉姐了(https://post.icpc-camp.org/d/715-2017-b-roads) 看了叉姐的对于我的几个问题的回复,我总算肯定了我的思路,而且叉姐还在下面给了标程,当时可以说心情非常愉悦: 听起来