BUPT 2022 Summer Training #1(2018 ICPC Asia Singapore Regional)
题目大意:一共有N个节点M条边,在前K个点中,编号为j的节点会在第(x⋅K+j)分钟产出物品(x≥0 and j=1,2,…,K),物品通过一条边的时间为1分钟,最终通过传送带运输到仓库N,求在这K个节点中最多能保持多少个节点运行而不会产生冲突(即不会在某分钟有两个及以上的物品出现在同一个节点)。
数据范围:1≤K≤N≤300; 0≤M≤1000
解题思路:最大流。
对每个节点拆分成K个节点,表示每个节点在第i分钟的情况,若某条边连接x和y,则对x的第i分钟与y的第i+1分钟建立一条权值为1的边(若i=K则对x的第K分钟与y的第1分钟建边),源点对于前K个节点的产出物品时间建立权值为1的边,对n节点的所有K分钟建立流向汇点权值为inf的边。(一定要是inf,因为仓库是可以两个及以上的物品同时到达)接着跑最大流即可。
赛后总结:赛时知道是网络流,思路其实也差不多出来了,但是感觉有问题(也有时间原因)就没再往下想下去。
参考代码:
#include<bits/stdc++.h> using namespace std; long long head[250000],num1=1,n,k,m,s,t,ans,deep[100000]; struct tu{ long long next,to,sco; }e[3000000]; void work(long long from,long long to,long long sco) { e[++num1].next=head[from]; e[num1].to=to; e[num1].sco=sco; head[from]=num1; } bool bfs() { memset(deep,0,sizeof(deep)); queue<long long> line; deep[s]=1; line.push(s); while(!line.empty()) { long long now=line.front(); line.pop(); for(long long i=head[now];i;i=e[i].next) { if(e[i].sco&&!deep[e[i].to]) deep[e[i].to]=deep[now]+1,line.push(e[i].to); } } return deep[t]; } long long dfs(long long now,long long in) { if(now==t) return in; long long out=0; for(long long i=head[now];i&∈i=e[i].next) { if(e[i].sco&&deep[e[i].to]==deep[now]+1) { long long res=dfs(e[i].to,min(in,e[i].sco)); in-=res; out+=res; e[i].sco-=res; e[i^1].sco+=res; } } if(out==0) deep[now]=0; return out; } int main() { cin>>n>>k>>m; for(long long i=1;i<=m;i++) { long long u,v; scanf("%lld%lld",&u,&v); for(long long j=0;j<k;j++) { long long from=u*k+j,nt=v*k+j+1; if(j==k-1) nt-=k; work(from,nt,1); work(nt,from,0); } } s=(n+1)*k,t=(n+1)*k+1; for(long long i=1;i<=k;i++) { work(s,i*k+(i-1),1); work(i*k+(i-1),s,0); } for(long long i=1;i<=k;i++) { work(n*k+(i-1),t,1e9); work(t,n*k+(i-1),0); } while(bfs()) { ans+=dfs(s,1e18); } cout<<ans<<endl; return 0; }

浙公网安备 33010602011771号