题解:
分操作讨论一下。
操作$1$:
两条路径走到同一个点原地爆炸。
由于要求点只能取一次,我们可以将点拆为入点和出点。
1.入点->出点,容量为$1$,费用为点权相反数;
2.上面的出点->下面的入点,容量为$1$,费用为0;
3.$S$->最上面一排入点,最下面一排出点->$T$,处理和$2$操作是一样的。
然后最大费用流。
操作$2$:
两条路径走到一条边上原地爆炸。
由于边只能取一次,点都不用拆。
上面点->下面点,容量为$1$,费用为下面点点权相反数。
然后最大费用流。
巨坑:两条路径可能相交于最下面的点,所以最下面一排->$T$的容量至少为$2$。
操作$3$:
瞎走。只要向下就不原地爆炸。
没啥好说的,上面点->下面点,容量正无穷,费用为下面点点权相反数。
然后最大费用流。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 3200 #define ll long long const int inf = 0x3f3f3f3f; const ll Inf = 0x3f3f3f3f3f3f3f3fll; 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; int a[45][45]; int _id(int x,int y) { return y+(x*(x-1)/2); } struct EG { int to,nxt; ll w,c; }e[60*N]; void ae(int f,int t,ll w,ll c) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].w = w; e[cnt].c = c; hed[f] = cnt; } ll 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,vis[S] = 1,fl[S] = Inf;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; } ll mcmf() { ll ret = 0; while(spfa()) { ret+=fl[T]*dep[T]; int u = T; while(u!=S) { e[pre[u]].w-=fl[T]; e[pre[u]^1].w+=fl[T]; u = fa[u]; } } return ret; } void init() { memset(hed,-1,sizeof(hed)); cnt = -1,S = 0,T = 3000; } void Case1() { init(); for(int i=1;i<=n;i++) { int x = _id(n,i); ae(S,x<<1,1,0); ae(x<<1,S,0,0); } for(int i=n;i<=n+m-1;i++) for(int j=1;j<=i;j++) { int x = _id(i,j); ae(x<<1,x<<1|1,1,-a[i][j]); ae(x<<1|1,x<<1,0,a[i][j]); } for(int i=n;i<n+m-1;i++) for(int j=1;j<=i;j++) { int x = _id(i,j); int y = _id(i+1,j); ae(x<<1|1,y<<1,1,0); ae(y<<1,x<<1|1,0,0); y = _id(i+1,j+1); ae(x<<1|1,y<<1,1,0); ae(y<<1,x<<1|1,0,0); } for(int i=1;i<=n+m-1;i++) { int x = _id(n+m-1,i); ae(x<<1|1,T,1,0); ae(T,x<<1|1,0,0); } printf("%lld\n",-mcmf()); } void Case2() { init(); for(int i=1;i<=n;i++) { int x = _id(n,i); ae(S,x,1,-a[n][i]); ae(x,S,0,a[n][i]); } for(int i=n;i<n+m-1;i++) for(int j=1;j<=i;j++) { int x = _id(i,j); int y = _id(i+1,j); ae(x,y,1,-a[i+1][j]); ae(y,x,0,a[i+1][j]); y = _id(i+1,j+1); ae(x,y,1,-a[i+1][j+1]); ae(y,x,0,a[i+1][j+1]); } for(int i=1;i<=n+m-1;i++) { int x = _id(n+m-1,i); ae(x,T,Inf,0); ae(T,x,0,0); } printf("%lld\n",-mcmf()); } void Case3() { init(); for(int i=1;i<=n;i++) { int x = _id(n,i); ae(S,x,1,-a[n][i]); ae(x,S,0,a[n][i]); } for(int i=n;i<n+m-1;i++) for(int j=1;j<=i;j++) { int x = _id(i,j); int y = _id(i+1,j); ae(x,y,Inf,-a[i+1][j]); ae(y,x,0,a[i+1][j]); y = _id(i+1,j+1); ae(x,y,Inf,-a[i+1][j+1]); ae(y,x,0,a[i+1][j+1]); } for(int i=1;i<=n+m-1;i++) { int x = _id(n+m-1,i); ae(x,T,Inf,0); ae(T,x,0,0); } printf("%lld\n",-mcmf()); } int main() { // freopen("digit1.in","r",stdin); n = rd(),m = rd(); for(int i=n;i<=n+m-1;i++) for(int j=1;j<=i;j++) a[i][j] = rd(); Case1(); Case2(); Case3(); return 0; }