我会在代码后面说一下我的两份代码的区别,所以其实可以不用看下面的代码;
TLE 50 分代码
#include <bits/stdc++.h>
#define debug cout<<"YES"<<endl
using namespace std;
const int inf=1e9;
const int N=81005,M=20000005;
int head[N],ver[M],len[M],nxt[M],fee[M],tot=1,S,T,P=0;
int pv[N],pe[N],n,m,p[45],c[105][45],dis[N],vis[N],mf=0,fl=0;
inline void add_edge(int x,int y,int z,int w){
++tot,nxt[tot]=head[x],head[x]=tot;
ver[tot]=y,len[tot]=z,fee[tot]=w;
++tot,nxt[tot]=head[y],head[y]=tot;
ver[tot]=x,len[tot]=0,fee[tot]=-w;
return ;
}
inline int spfa(){
memset(pv,0,sizeof pv),
memset(pe,0,sizeof pe),
memset(dis,0x3f,sizeof dis),
memset(vis,0,sizeof vis);
queue<int>q;q.push(S);
vis[S]=1,dis[S]=0;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i;i=nxt[i]){
if(len[i] && dis[ver[i]]>dis[u]+fee[i]){
dis[ver[i]]=dis[u]+fee[i];
pv[ver[i]]=u,pe[ver[i]]=i;
if(!vis[ver[i]]) vis[ver[i]]=1,q.push(ver[i]);
}
}
}
return pv[T];
}
void EdmondKarps(){
while(spfa()){
int dLen=0,flow=inf,now=T;
while(now!=S){
dLen+=fee[pe[now]];
flow=min(flow,len[pe[now]]);
now=pv[now];
}
now=T;
while(now!=S){
len[pe[now]]-=flow,
len[pe[now]^1]+=flow;
now=pv[now];
}
fl+=flow;
mf=mf+flow*dLen;
int g=pv[T]%P,k=(pv[T]+P-1)/P;
if(g) {
int s=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=p[i];++j)
++s,add_edge(m*P+s,pv[T]+1,1,c[k][i]*(g+1));
}
}
return ;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&p[i]),P+=p[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&c[j][i]);
S=m*P+P+1,T=m*P+P+2;
int s=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=p[i];++j)
++s,add_edge(S,m*P+s,1,0);
for(int i=1;i<=m*P;++i) add_edge(i,T,1,0);
for(int i=1;i<=m*P;i+=P){
s=0;
for(int j=1;j<=n;++j)
for(int k=1;k<=p[j];++k)
++s,add_edge(m*P+s,i,1,c[i/P+1][j]);
}
EdmondKarps();
printf("%d\n",mf);
return 0;
}
AC 代码 :
#include <bits/stdc++.h>
#define debug cout<<"YES"<<endl
using namespace std;
const int inf=1e9;
const int N=81005,M=15000005;
int head[N],ver[M],len[M],nxt[M],fee[M],tot=1,S,T,P=0;
int pv[N],pe[N],n,m,p[45],c[105][45],dis[N],vis[N],mf=0,fl=0;
inline void add_edge(int x,int y,int z,int w){
++tot,nxt[tot]=head[x],head[x]=tot;
ver[tot]=y,len[tot]=z,fee[tot]=w;
++tot,nxt[tot]=head[y],head[y]=tot;
ver[tot]=x,len[tot]=0,fee[tot]=-w;
return ;
}
inline int spfa(){
memset(pv,0,sizeof pv),
memset(pe,0,sizeof pe),
memset(dis,0x3f,sizeof dis),
memset(vis,0,sizeof vis);
queue<int>q;q.push(S);
vis[S]=1,dis[S]=0;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
for(int i=head[u];i;i=nxt[i]){
if(len[i] && dis[ver[i]]>dis[u]+fee[i]){
dis[ver[i]]=dis[u]+fee[i];
pv[ver[i]]=u,pe[ver[i]]=i;
if(!vis[ver[i]]) vis[ver[i]]=1,q.push(ver[i]);
}
}
}
return pv[T];
}
void EdmondKarps(){
while(spfa()){
int dLen=0,flow=inf,now=T;
while(now!=S){
dLen+=fee[pe[now]];
flow=min(flow,len[pe[now]]);
now=pv[now];
}
now=T;
while(now!=S){
len[pe[now]]-=flow,
len[pe[now]^1]+=flow;
now=pv[now];
}
fl+=flow;
mf=mf+flow*dLen;
int g=pv[T]%P,k=(pv[T]+P-1)/P;
if(g) {
for(int i=1;i<=n;++i)
add_edge(m*P+i,pv[T]+1,1,c[k][i]*(g+1));
}
}
return ;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&p[i]),P+=p[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&c[j][i]);
S=m*P+n+1,T=m*P+n+2;
for(int i=1;i<=n;++i)
add_edge(S,m*P+i,p[i],0);
for(int i=1;i<=m*P;++i) add_edge(i,T,1,0);
for(int i=1;i<=m*P;i+=P){
for(int j=1;j<=n;++j)
add_edge(m*P+j,i,1,c[i/P+1][j]);
}
EdmondKarps();
printf("%d\n",mf);
return 0;
}
区别只有 TLE 的代码将一种菜的需要做多份的时候拆成很多个点,其他优化都是一样的。这样写的话点数只比 AC 代码多了最多 800 个点,而点数的主要负担是厨师做到第 i 道菜的 m⋅∑p 的 32000 个点。为什么这样就会 TLE 呢?本地运行了一下效率大概差了 10 倍左右?