标签:新建 include oid 它的 spfa $0 问题 mem 最大
题解:
最大费用流。
每个点向后面不小于它的点建一条容量为$1$,费用$-1$的边。
$S$向所有点建容量为$1$的入边(费用为$-1$),所有点向$T$建容量为$1$的出边(费用为$0$)。
然后最大费用流。
由于第一次得到的通路是费用最小的,这个费用的相反数就是问题一的答案。
然后继续跑,跑出几个最小费用,问题二的答案就加几。
第三问只要重新建图,然后$S$只向$1$,只有$n$向$T$,容量正无穷。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 1050 const int inf = 0x3f3f3f3f; inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){c=10*c+ch-‘0‘;ch=getchar();} return f*c; } int n,m,S,T,hed[N],cnt=-1,a[N]; struct EG { int to,nxt,w,c; }e[4*N*N]; void ae(int f,int t,int w,int c) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].w = w; e[cnt].c = c; hed[f] = cnt; } void AE(int f,int t,int w,int c) { ae(f,t,w,c); ae(t,f,0,-c); } int dep[N],fl[N]; int pre[N],fa[N]; bool vis[N]; queue<int>q; bool spfa() { memset(dep,0x3f,sizeof(dep)); dep[S]=0,fl[S]=inf,vis[S]=1;q.push(S); while(!q.empty()) { int u = q.front(); q.pop(); for(int j=hed[u];~j;j=e[j].nxt) { int to = e[j].to; if(e[j].w&&dep[to]>dep[u]+e[j].c) { dep[to] = dep[u]+e[j].c; fl[to] = min(fl[u],e[j].w); pre[to] = j,fa[to] = u; if(!vis[to]) { vis[to] = 1; q.push(to); } } } vis[u] = 0; } return dep[T] != inf; } void mcmf(bool typ) { int ct = 0; bool fd = 0; while(spfa()) { if(!fd)m = fl[T]*dep[T],fd=1; if(fl[T]*dep[T]==m)ct++; else break; int u = T; while(u!=S) { e[pre[u]].w-=fl[T]; e[pre[u]^1].w+=fl[T]; u = fa[u]; } } if(!typ) { printf("%d\n%d\n",-m,ct); }else { printf("%d\n",ct); } } void sol1() { memset(hed,-1,sizeof(hed)); for(int i=1;i<=n;i++) { AE(S,i<<1,1,-1); AE(i<<1|1,T,1,0); AE(i<<1,i<<1|1,1,0); } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(a[j]>=a[i]) AE(i<<1|1,j<<1,1,-1); mcmf(0); } void sol2() { memset(hed,-1,sizeof(hed)); for(int i=2;i<n;i++) { AE(S,i<<1,1,-1); AE(i<<1|1,T,1,0); AE(i<<1,i<<1|1,1,0); } AE(S,2,inf,-1); AE(2,3,inf,0); AE(3,T,1,0); AE(S,n<<1,1,-1); AE(n<<1,n<<1|1,inf,0); AE(n<<1|1,T,inf,0); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(a[j]>=a[i]) AE(i<<1|1,j<<1,1,-1); mcmf(1); } int main() { n = rd();S = 0,T = 1; for(int i=1;i<=n;i++)a[i] = rd(); sol1(); sol2(); return 0; }
标签:新建 include oid 它的 spfa $0 问题 mem 最大
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10256687.html