两个等价代码,为什么一个TLE一个AC?

P3381 【模板】最小费用最大流

我有个猜想,你第一个代码break之后是不是就不会执行本次循环的```arc[u] = back[arc[u]]```了
by Edgebright @ 2023-09-22 17:18:03


这样的话下次搜进来,你的当前弧是满的
by Edgebright @ 2023-09-22 17:19:45


**这是我没看代码时写的** 你是不是一个开了o2优化,一个没开o2优化?因为o2优化会把for里的i++,j--变成++i,++j,时间大概快一倍(本人亲测过) **这是我浅显看了代码后写的** 不仅有上面原因,把判断放外面会减小1点点计算量
by derekyang326 @ 2023-09-22 17:21:35


@[derekyang326](/user/1094313) 都说了不是常数问题了
by Bingxiu @ 2023-09-22 17:29:27


@[derekyang326](/user/1094313) 都说了不是常数问题 我不认为你有看懂费用流代码的能力
by hjqhs @ 2023-09-22 17:34:15


@[Edgebright](/user/762588) 经过测试,尽管这个确实有区别,但不是T的原因
by Edgebright @ 2023-09-22 18:25:43


``` bool broke = 0; bool test(int sum, int maxi) { if(!broke) return sum<maxi; else if(sum < maxi) return 1; else assert(0); } int dfs(int u,int maxi) { if (u == t) return maxi; int sum=0,flow;in[u]=true; for (; arc[u]&&test(sum, maxi); arc[u] = back[arc[u]]) { v = to[arc[u]]; if (!in[v] && dist[v] == dist[u] + c[arc[u]]) { flow= dfs(v,std::min(w[arc[u]], maxi - sum)); cg += flow* c[arc[u]], w[arc[u]] -= flow, w[arc[u] ^ 1] += flow, sum += flow; if(sum >= maxi){ broke = 1; break; } } } in[u]=false; return sum; } ``` 实测assert被触发了。这说明有些情况逃过了break但是被循环里的判断挡住了。
by Edgebright @ 2023-09-22 18:35:10


只有一种可以,就是maxi=0的情况。你的TLE代码会跑一遍循环然后break,AC代码会之间跳过。 特判maxi=0,实测AC.
by Edgebright @ 2023-09-22 18:49:57


@[Edgebright](/user/762588) 这个怎么解释 ```cpp //AC #include<bits/stdc++.h> #define ui unsigned int #define au arc[u] using namespace std; const int nn=5002,mm=100005; bool in[nn]; int n,m,s,t,u,v,fg,cg,tot=1; int dist[nn],arc[nn],last[nn]; int to[mm],w[mm],c[mm],back[mm]; queue<int>q; void link(int u,int v,int weight,int cost){ to[++tot]=v,w[tot]=weight,c[tot]=cost; back[tot]=last[u],last[u]=tot; } bool spfa(){ memcpy(arc,last,sizeof last), memset(dist,0x3f,sizeof dist); for(q.push(s),in[s]=true,dist[s]=0;!q.empty();q.pop(),in[u]=false){ for(int i=last[u=q.front()];i;i=back[i]){ if(w[i]&&dist[v=to[i]]>dist[u]+c[i]){ dist[v]=dist[u]+c[i]; if(!in[v])q.push(v),in[v]=true; } } } return dist[t]!=1061109567; } int dinic(int u,int maxi){ if(u==t)return maxi; int sum=0,f;in[u]=true; for(;au;au=back[au]){ v=to[au]; if(!in[v]&&dist[v]==dist[u]+c[au]){ f=dinic(v,min(maxi-sum,w[au])); sum+=f,cg+=f*c[au]; w[au]-=f,w[au^1]+=f; } if(sum==maxi)break; } in[u]=false; return sum; } int main(){ int w,c; for(scanf("%d%d%d%d",&n,&m,&s,&t);m--;) scanf("%d%d%d%d",&u,&v,&w,&c), link(u,v,w,c),link(v,u,0,-c); while(spfa()) for(int flow;(flow=dinic(s,INT_MAX));) fg+=flow; printf("%d %d",fg,cg); return 0; } ``` ```cpp //TLE #include<bits/stdc++.h> #define ui unsigned int #define au arc[u] using namespace std; const int nn=5002,mm=100005; bool in[nn]; int n,m,s,t,u,v,fg,cg,tot=1; int dist[nn],arc[nn],last[nn]; int to[mm],w[mm],c[mm],back[mm]; queue<int>q; void link(int u,int v,int weight,int cost){ to[++tot]=v,w[tot]=weight,c[tot]=cost; back[tot]=last[u],last[u]=tot; } bool spfa(){ memcpy(arc,last,sizeof last), memset(dist,0x3f,sizeof dist); for(q.push(s),in[s]=true,dist[s]=0;!q.empty();q.pop(),in[u]=false){ for(int i=last[u=q.front()];i;i=back[i]){ if(w[i]&&dist[v=to[i]]>dist[u]+c[i]){ dist[v]=dist[u]+c[i]; if(!in[v])q.push(v),in[v]=true; } } } return dist[t]!=1061109567; } int dinic(int u,int maxi){ if(u==t)return maxi; int sum=0,f;in[u]=true; for(;au;au=back[au]){ v=to[au]; if(!in[v]&&dist[v]==dist[u]+c[au]){ f=dinic(v,min(maxi-sum,w[au])); sum+=f,cg+=f*c[au]; w[au]-=f,w[au^1]+=f; if(sum==maxi)break; } } in[u]=false; return sum; } int main(){ int w,c; for(scanf("%d%d%d%d",&n,&m,&s,&t);m--;) scanf("%d%d%d%d",&u,&v,&w,&c), link(u,v,w,c),link(v,u,0,-c); while(spfa()) for(int flow;(flow=dinic(s,INT_MAX));) fg+=flow; printf("%d %d",fg,cg); return 0; } ``` 纯粹只是把break调出来,而只有在大括号里面sum才会被修改,才有可能break啊,所以在不在里面是一样的。
by 千年知乎_天才 @ 2023-09-23 23:36:47


而且这不是巧合,另一道费用流的题,也是把break调出来就过了 https://www.luogu.com.cn/record/125835910 https://www.luogu.com.cn/record/125835940
by 千年知乎_天才 @ 2023-09-23 23:39:49


| 下一页