网络流强化-HDU2732
第一次遇到加了“多余”的边会导致WA的——在我看来是很多余,见代码191行
之后会思考为什么,想出来再更。
问题弄明白了,如果你在连接边连了一条到没有柱子的点的边,这个没有柱子的点是不可能连到终点的,所以在BFS划分层次的时候就不会设置它的层次,也就是说默认为0,刚好和终点的层次相同,那么当走到这个点的时候,由于他和其他的点完全不连通,所以就会进入层次更新关节,里面有句话是是
if (--num[d[u]] == ) break; // gap 优化
所以导致直接就退出了,没有给终点来一次机会——终点为层次0做出了唯一一次贡献,但是被这个来历不明的点“狸猫换太子”了。
解决办法有两种:
1:将起始层次设置为1
2:保证连接的边都是实际能走的路
好的,第一种错了,第一种只能保证第四个样例是对的。
让我查了错再更。2019年8月17日15:16:24
初步的查错是他居然过不了样例4——原来之前遗留的d可能会被用到没有柱子的点(实验前提:起始层次为1),所以我的d数组也每次都重置。 能过样例,但是WA了。
2019年8月17日22:44:50更新:
查出来了,原因还是在更新层次的时候,涉及到了没有柱子的点,这时候没有柱子的点的层次是0,会作为剩余连接点中层次最低的点去更新当前点的层次值——显然不合理,因为层次值每次是应该变得更大的。
2019年8月18日10:02:50
其实昨天就已经又查出来一个问题了:我是想让终点的起始层次为0,然后不连接非法(没有柱子)的点,然后还把num、vis、d三个数组一起初始化为0——修改模板。但是提交后WA了。
今天查错:发现如果起点连接了一个蜥蜴的点,但是这个蜥蜴的点和终点并不连通,这时候会出现这个蜥蜴的点层次依旧为0——好的,等到起点要走这个点发现走不通,这个点是不是要执行--num[d[u]]的操作——刚好和终点的层次撞上了。
所以:网络流建图
确保所有的点都要和终点连通——这样才是合法的点
至于这样的组合能过全部样例不能过单个样例:for(i=0;i<=t;++i) vis[i]=num[i]=0; d[t] = 0;
只能说之前的样例会让d[45]的值不是0吧。
只有这样才能保证是完全对的: for(i=0;i<=t;++i) vis[i]=num[i]=d[i]=0; d[t] = 1;
我们会发现num[0] = 0,d[45]=0,45号点不能走通,--num[0]= -1 != 0 不会跳出循环 所以能继续执行
单个样例:
.L..L.LL
.LL..LL.
..LL....
LL..LL.L
......LL
.LL..L..
.L.....L
...LL...
L.LL...L
L..L...L
.L.L....
lizards.in CASE 20
我觉得最好的办法是完全排除非法的点(无柱子的点,有柱子但是不能逃出火场的点)
或者简单一点把所有的d一开始置为inf,那么对于非法的点,由于d=inf,所以在选择剩余距离最小的点中根本就不会选择这个点。
这样一来,最后起点无法增广到终点的情况下,起点的d最终会被突破上限而最终跳出循环(或者中途发现中间层次缺失跳出循环)。
最终成品:
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define maxe 25600 //pay 双向边 一共10万条路 双向就是20万 反边就是40万
#define maxv 1024 //pay
#define maxn 25 //pay
#define sc scanf
#define pt printf
#define rep(i,a,b) for(int i=(a);i<(b);++i)
const int inf = 0x3f3f3f3f;
int cg,sp,ins; //cg change sp是总流量 ins是加速回溯点
int N,M,T,D ,s,t,delta,UP_LIMIT;
int q[maxv],fro,rea;
typedef struct ed{
int v,nxt,cap; //dis
}ed;
ed e[maxe];
int tot,head[maxv],cur[maxv],vis[maxv],bk[maxv],d[maxv],num[maxv]; //
int mi(int a,int b) {return a<b?a:b;}
int mx(int a,int b) {return a>b?a:b;}
void add(int u,int v,int cap)
{
e[tot].v=v; e[tot].nxt=head[u];
/*e[tot].dis=dis;*/ e[tot].cap=cap;
head[u]=tot++; e[tot].v=u; e[tot].nxt=head[v];
/*e[tot].dis=-dis;*/ e[tot].cap=;
head[v]=tot++;
}
// 仅有一次的BFS为ISAP节省了不少时间
bool bfs()
{
//数组模拟queue
int u,v,i,my_all = t;
for(i=;i<=my_all;++i) vis[i]=num[i]=; //无须一定是my_all,涉及所有即可~~~~~~~~~~~~~~~~~~
for(i=;i<=my_all;++i) d[i]=UP_LIMIT; //UP_LIMIT的设定是比最高的层次大1
fro = rea = ;
q[rea] = t; ++rea;
vis[t] = ;
d[t] = ;
++num[d[t]];
while (rea>fro)
{
u = q[fro]; ++fro;
for (i=head[u]; i!=-; i=e[i].nxt)
{
v=e[i].v;
if (!vis[v] && e[i^].cap )
{
vis[v] = true;
d[v] = d[u] + ;
++num[d[v]];
q[rea] = v; ++rea;
//pt("普度众生 u=%d,v=%d,d[u]=%d,d[v]=%d\n",u,v,d[u],d[v]);
}
}
}
int last_ed=-;
//把连接了到不了终点的点的边都去除
for(u=;u<=my_all;++u)
{
if(!vis[u]) continue;
for (i=head[u]; i!=-; i=e[i].nxt)
{
v=e[i].v;
if(!vis[v])
{
if(i==head[u]){
head[u] = e[i].nxt;
continue;
}
else{
e[last_ed].nxt = e[i].nxt;
continue;
}
}
last_ed = i;
}
}
return vis[s];
}
// 增广
int augment()/*单源单汇 不用查这个*/
{
int flow = inf, i;
cg = t;
// 从汇点到源点通过 p 追踪增广路径, flow 为一路上最小的残量
while (cg != s) {
i = bk[cg];
if(flow>=e[i].cap)
{
flow = e[i].cap;
ins = e[i^].v;
//用来加速寻找,在最小流量断开的地方重新开始寻找
//嗯,等一下 我这个是从终点往起点寻找,而确定增光路径是从起点到终点
//那么起点是河流的上游,那么回溯的河段应该尽可能的往上游靠近
//所以应该将flow>e[i].cap的大于号改成大于等于号
}
cg = e[i^].v;
}
cg = t;
// 从汇点到源点更新流量
while (cg != s) {
i = bk[cg];
e[i].cap -= flow;
e[i^].cap += flow;
cg = e[i^].v;
}
return flow;
}
//由于每次修改层次的时候,都是在到剩下子节点的距离中挑选最短的加1 所以层次分明不会出现死循环
int max_flow()
{
int flow = ,i,u,v;
bool advanced;
if(bfs()==false) return ;
// pt("零层妖塔=%d\n",num[0]);
//不一定是从s到t,你要知道统计每个层次的点的个数是全局统计的
u = s;
memcpy(cur, head, sizeof(head));
while (d[s] < UP_LIMIT) //UP_LIMIT的设定是比最高的层次大1
//终点是0,那么起点所在层次最多是N-1 同理,不是d[s]<t
{
if (u == t)
{
flow += augment();
u = ins; //pay speed up
}
advanced = false;
for (i = cur[u]; i!=-; i=e[i].nxt)
{
v = e[i].v;
//pt("SELECT: %d -> %d\n",u,v);
if (e[i].cap && d[u] == d[v] + )
{
advanced = true;
bk[v] = i;
cur[u] = i;
// pt("%d -> %d ::d[u]=%d,d[v]=%d\n",u,v,d[u],d[v]);
u = v;
break;
}
}
if (!advanced)
{ // retreat
int base = UP_LIMIT; //UP_LIMIT的设定是比最高的层次大1
for (i = head[u]; i != -; i=e[i].nxt)
{
if (e[i].cap&&base>d[e[i].v])
{
cur[u] = i;
base = d[e[i].v];
}
} if (--num[d[u]] == )
{
//pt("u=%d,d=%d\n",u,d[u]);
//pt("BREAK FROM HERE\n");
break; // gap 优化
}
++num[d[u] = base+];
//pt("------------------我来增加层次%d:%d\n",m+1,u);
//我以前一直在想 如果没有找到怎么办呢 现在发现原来找不到的话距离会被赋成base+1
//—— 比上界还高 所以接下来不会再访问到这个点 这个点也没有机会被减成0了——不会莫名其妙地break,哈哈哈
if (u != s)
{
//pt("from %d ",u);
u = e[bk[u]^].v;
//pt("return to %d\n",u);
}
else
{
// pt("STILL AT S:%d\n",s);
}
}
}
return flow;
} void init()
{
tot=;
memset(head,-,sizeof(head)); //pay
}
char times[maxn][maxn],haves[maxn][maxn];
//最大流部分没有什么问题了 关键在于终点源点、编号分配、题目理解建图上面
//切记:不要建立无用的边!! 包括连接不到的点 和不和终点连通的点
//确保所有的点都要和终点连通——这样才是合法的点
int main()
{
freopen("in.txt","r",stdin);
sc("%d",&T);
/*数据初始化区*/
s=, bk[]=-; /*变量存放区*/
int i,j,u,v,id,can,kase=,who,LI; while(T--)
{
++kase;
sc("%d%d",&N,&D); /*数据初始化区*/
init(); sp = LI = ; /*数据读取区*/
for(i=;i<N;++i) sc("%s",times[i]);
for(i=;i<N;++i) sc("%s",haves[i]); /*关键数据赋值区*/
M=strlen(times[]); delta = (N)*(M); t=*delta+; s=*delta;
UP_LIMIT = *delta + ;
//说明:这个是层次的无法达到的上界,所以一共有N个点的时候,
//如果从0开始编号,那么上界就是N;如果从1开始编号,上界就是N+1 /*建图区*/
for(i=;i<N;++i) for(j=;j<M;++j)
{
can = times[i][j]-'';
if(can==) continue;
id = i*(M) + (j);
add(id,id + delta,can );
}
for(i=;i<N;++i) for(j=;j<M;++j)
{
if(haves[i][j]!='L') continue;
id = i*(M) + (j);
add(s,id,);
++LI;
}
for(i=;i<N;++i) for(j=;j<M;++j)
{
if(times[i][j]=='') continue; //这里写成过有没有蜥蜴的那个矩阵
id = i*(M) + (j);
if(i-D<||i+D>N-||j-D<||j+D>M-) add(id+delta,t,inf);
for(u=mx(,i-D);u<=mi(N-,i+D);++u) for(v=mx(,j-D);v<=mi(M-,j+D);++v)
{
//下面这一行居然是决胜关键 可是废点不是完全不会走吗
if(times[u][v]=='') continue;
if(u==i&&v==j) continue;
//这是最终确定的可跳跃方式,他这个居然是曼哈顿距离 待会交一下看一下是不是这样 wa 了
if(abs(u-i)+abs(v-j)>D) continue;
who = u*(M) + (v);
add(id+delta,who,inf);
}
} /*答案处理区*/
sp = max_flow();
int ans = LI-sp;
if(ans==) printf("Case #%d: no lizard was left behind.\n",kase);
else if(ans==) printf("Case #%d: 1 lizard was left behind.\n",kase);
else printf("Case #%d: %d lizards were left behind.\n",kase,ans);
}
return ;
} /**
* 友情链接:
* http://www.renfei.org/blog/isap.html 解释ISAP原理
* https://www.cnblogs.com/bosswnx/p/10353301.html 使用的数据结构和我的比较相近
*/
网络流强化-HDU2732的更多相关文章
- 网络流强化-HDU 3338-上下界限制最大流
题意是: 一种特殊的数独游戏,白色的方格给我们填1-9的数,有些带数字的黑色方格,右上角的数字代表从他开始往右一直到边界或者另外一个黑格子,中间经过的白格子的数字之和要等于这个数字:左下角的也是一样的 ...
- 网络流强化-UVA10480
做这道题,自己先是想了好几种找被割的边的方法——都被否决了. 后来发现是最小割:只要一条边的两端在不同的点集里面就代表是被割掉的满流边(这些满流边的流量和等于最大流的流量与最小割的权值和). 但是之前 ...
- 网络流强化-HDU4280
数组没开够居然显示TLE而不是RE,自己觉得好的优化的方法没什么用…… //http://www.renfei.org/blog/isap.html 带解释的 //https://www.cnblog ...
- 网络流强化-POJ2516
k种货物分开求解最小费用最大流,主要减少了寻找最短路的时间. #include<queue> #include<cstdio> #include<cstring> ...
- HDU2732 Leapin' Lizards 网络流 最大流 SAP
原文链接http://www.cnblogs.com/zhouzhendong/p/8362002.html 题目传送门 - HDU2732 题意概括 给你一个网格,网格上的一些位置上有一只蜥蜴,所有 ...
- hdu2732 Leapin' Lizards (网络流dinic)
D - Leapin' Lizards Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u ...
- POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流)
POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流) Description Yo ...
- 【算法】【网络流24题】巨坑待填(成功TJ,有时间再填)
------------------------------------------------------------------------------------ 17/24 --------- ...
- HDU2732 Leapin' Lizards —— 最大流、拆点
题目链接:https://vjudge.net/problem/HDU-2732 Leapin' Lizards Time Limit: 2000/1000 MS (Java/Others) M ...
随机推荐
- [Java] 歐付寶金流串接教學
前言: 很多接案的人,都會碰到需要接金流的時候.而歐付寶是個台灣的金流平台. 這邊記錄下,串接的心得.我用的語言是Java, 採liferay這個portal平台,不過這份教學當然適合servlet. ...
- Spring事务嵌套引发的问题--Transaction rolled back because it has been marked as rollback-only
转载https://blog.csdn.net/f641385712/article/details/80445912 读了两边才找到问题
- BUUCTF--SimpleRev
测试文件:https://buuoj.cn/files/7458c5c0ce999ac491df13cf7a7ed9f1/SimpleRev?token=eyJ0ZWFtX2lkIjpudWxsLCJ ...
- MVC项目集成swagger
1.创建WebAPI项目解决方案 2.使用nuget引入Swashbuckle包 引入Swashbuckle包后App_Start文件夹下会多出一个SwaggerConfig文件 3.添加接口注释 项 ...
- 03.LinuxCentOS系统root目录LVM磁盘扩容
根目录LVM扩容操作步骤: [root@centos7 ~]# df -lh文件系统 容量 已用 可用 已用% 挂载点/dev/mapper/centos-root 50G 7.7G 43G 6% / ...
- Linux手册页内容
总用9页 man1:可执行程序或shell命令 man2:系统调用(kernel提供的函数) man3:库调用(程序库中的函数) man4:/dev中的特殊文件 ...
- uniq 去除重复行
1.命令功能 uniq可以输出或忽略文件中的重复行,经常需要使用sort先对文件进行排序,然后使用uniq去重并计数. 2.语法格式 uniq option input uniq 选项 ...
- 【LeetCode】未分类(tag里面没有)(共题)
[334]Increasing Triplet Subsequence (2019年2月14日,google tag)(greedy) 给了一个数组 nums,判断是否有三个数字组成子序列,使得子序列 ...
- css图像拼合技术(精灵图)
CSS图像拼合技术 1.图像拼合 图像拼合技术就是单个图像的集合. 有很多图片的网页可能会需要很多时间来加载和生成多个服务器的请求. 使用图像拼合会降低服务器的请求数量,并节省带宽. 图像拼合实例 有 ...
- R语言把DataFrame的一行变成向量
在R语言里面,DataFrame的一列数据本质上可以认为是一个向量或列表,但是一行数据不是. 今天有一个31列的数据集,由于放在第一行的变量名格式不规范,读入数据的时候不能顺带读入变量名.于是跳过首行 ...