[最小费用最大流]JZOJ 4802 探险计划
分析
看题,数据小,不难想到DP
然后想一下,DP的复杂度很高(根本不能打好不好!)
然后发现点边被限制经过次数,就想到了最小费用流
我们把数字拆成入点和出点,费用为原数字,流量要看是哪个任务,任务1则为1,任务2则为无限
然后向上下可到达的点连边,费用0,流量1
对于任务1,与源汇的边流量为1,任务2则为无限
然后要判断增广次数,最多为m次
点数较多,需要用ZKW,这里偷懒开了O2直接EK睡过去了
#pragma GCC optimize(2) #include <iostream> #include <cstdio> #include <queue> #include <memory.h> using namespace std; const int N=2e4+10; const int Inf=2147483647; struct Edge { int u,v,nx,c,w; }g[5*N]; int cnt=1,list[N],a[200][200],b[200][200],d[N],f[N]; bool vis[N]; int n,m,s,t,ans,ans1; void Add(int u,int v,int w,int c) { g[++cnt]=(Edge){u,v,list[u],c,w};list[u]=cnt; g[++cnt]=(Edge){v,u,list[v],0,-w};list[v]=cnt; } bool BFS() { queue<int> q; while (!q.empty()) q.pop(); memset(d,0x3f,sizeof d); q.push(s);d[s]=0;vis[s]=1; while (!q.empty()) { int u=q.front();q.pop(); for (int i=list[u];i;i=g[i].nx) if (g[i].c&&d[u]+g[i].w<d[g[i].v]) { d[g[i].v]=d[u]+g[i].w; f[g[i].v]=i; if (!vis[g[i].v]) q.push(g[i].v); vis[g[i].v]=1; } vis[u]=0; } return d[t]!=0x3f3f3f3f; } void MCF() { int x=t,mf=Inf; while (f[x]) { mf=min(mf,g[f[x]].c); x=g[f[x]].u; } x=t;ans+=d[t]; while (f[x]) { g[f[x]].c-=mf;g[f[x]^1].c+=mf; x=g[f[x]].u; } } void C_Dinic() { int i=0; while (BFS()) { MCF(); i++; if (i==m) return; } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m+i-1;j++) scanf("%d",&a[i][j]),b[i][j]=++t; s=0; for (int i=1;i<=m;i++) Add(0,b[1][i]*2-1,0,Inf),Add(b[1][i]*2-1,b[1][i]*2,a[1][i],Inf); for (int i=2;i<=n;i++) for (int j=1;j<=m+i-1;j++) { if (j>1) Add(b[i-1][j-1]*2,b[i][j]*2-1,0,1); if (j<m+i-1) Add(b[i-1][j]*2,b[i][j]*2-1,0,1); Add(b[i][j]*2-1,b[i][j]*2,a[i][j],Inf); } t=t*2+1; for (int i=1;i<=m+n-1;i++) Add(b[n][i]*2,t,0,Inf); C_Dinic(); ans1=ans;ans=0; cnt=1;memset(list,0,sizeof list); for (int i=1;i<=m;i++) Add(0,b[1][i]*2-1,0,1),Add(b[1][i]*2-1,b[1][i]*2,a[1][i],1); for (int i=2;i<=n;i++) for (int j=1;j<=m+i-1;j++) { if (j>1) Add(b[i-1][j-1]*2,b[i][j]*2-1,0,1); if (j<m+i-1) Add(b[i-1][j]*2,b[i][j]*2-1,0,1); Add(b[i][j]*2-1,b[i][j]*2,a[i][j],1); } for (int i=1;i<=m+n-1;i++) Add(b[n][i]*2,t,0,1); C_Dinic(); printf("%d\n%d\n",ans,ans1); }
在日渐沉没的世界里,我发现了你。