問題の意味
それは、台形の数字を持っています
ラダーは有し\(N- \)行、最初の行\(M \)列、各行前の行より複数。
そこ\(M \)それぞれパスの端部に台形の頂部からストリップの第一行\(M \)出発点として要素、それぞれ左下や右下に移動することができます。
以下の3つの条件に対する回答が満たされたとき、それぞれ、\(M \)デジタルサムパスの最大値。
- \(M \)経路は相互に排他的です。
- \(M \)パスは、エッジが交差せず、交点であることができます。
- \(M \)パスが交差する点であってもよい、エッジが交差してもよいです。
思考
実際DAG内の質問は、さまざまなバリエーションのパスをばらばら。
最初の質問、ルーチンに従って、各点は一度だけ現れることができ、その後、各点に入れ点及びOut点、インとアウト点の間にも容量\(1 \)の、考慮\( 0 \)側、ライン上の最大コストの最大フローを実行しています。
2番目の質問、内と外のポイントなしで構築されたが、我々は、冗長構成図を避けるために持ってきた可能性があり、あなたが代わりにエッジ容量ポイントへの直接指すことができます\(INF \) 、元のような他のもの。注意最大流量エッジ重みが残留ネットワーク上で直接実行した後、次いで増強パスを見つけることができなかったので、変更することができません。
3番目の質問、起動したい\(DPを\)指定されたタイトルです....しかし、ソースから除いて...いくつかの顔を入れて(S \)\練習のうち外側のエッジ、すべての側面右側が置き換えられます\(INF \) 。(もちろん、逆側を除きます)。
コード
#include<bits/stdc++.h>
using namespace std;
const int _=60+7;
const int __=1202+7;
const int ___=3760+7;
const int inf=0x3f3f3f3f;
int n,m,S,T,a[_][_],num[_][_],dis[__],ans,cnt;
int lst[__],nxt[___],to[___],c[___],w[___],bk[___],tot=1;
bool vis[__],mst[___],cha[___];
queue<int> q;
void init(){
cin>>m>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=m+i-1;j++){
scanf("%d",&a[i][j]);
num[i][j]=++cnt;
}
}
S=(m+m+n-1)*n+1; T=S+1;
}
void add(int x,int y,int cap,int wgt){
if(x==S) mst[tot+1]=1;
if(y==x+cnt||y==T) cha[tot+1]=1;
nxt[++tot]=lst[x]; to[tot]=y; c[tot]=cap; w[tot]=wgt; lst[x]=tot; bk[tot]=cap;
nxt[++tot]=lst[y]; to[tot]=x; c[tot]=0; w[tot]=-wgt; lst[y]=tot;
}
void link(){
for(int i=1;i<=m;i++)
add(S,num[1][i],1,a[1][i]);
for(int i=1;i<=m+n-1;i++)
add(num[n][i]+cnt,T,1,0);
for(int i=1;i<n;i++)
for(int j=1;j<=m+i-1;j++){
add(num[i][j]+cnt,num[i+1][j],1,a[i+1][j]);
add(num[i][j]+cnt,num[i+1][j+1],1,a[i+1][j+1]);
}
for(int i=1;i<=cnt;i++)
add(i,i+cnt,1,0);
}
bool SPFA(){
for(int i=1;i<=T;i++){ dis[i]=-inf; vis[i]=0; }
while(!q.empty()) q.pop();
dis[S]=0; q.push(S);
while(!q.empty()){
int u=q.front(); q.pop();
vis[u]=0;
for(int i=lst[u];i;i=nxt[i]){
int v=to[i];
if(!c[i]||dis[v]>=dis[u]+w[i]) continue;
dis[v]=dis[u]+w[i];
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
return dis[T]!=-inf;
}
int dfs(int u,int flow){
if(u==T) return flow;
int rest=flow; vis[u]=1;
for(int i=lst[u];i;i=nxt[i]){
int v=to[i];
if(vis[v]||!c[i]||dis[v]!=dis[u]+w[i]) continue;
int cst=dfs(v,min(rest,c[i]));
if(cst==0) dis[v]=-inf;
else{
c[i]-=cst; c[i^1]+=cst;
rest-=cst; ans+=cst*w[i];
}
}
return flow-rest;
}
void Dinic(){
ans=0;
int flow;
while(SPFA())
do{
flow=dfs(S,inf);
}while(flow);
}
void change(int ty){
if(ty==2){
for(int i=2;i<=tot;i+=2){
if(cha[i]) c[i]=inf;
else c[i]=bk[i];
c[i^1]=0;
}
}
else{
for(int i=2;i<=tot;i+=2){
if(!mst[i]) c[i]=inf;
else c[i]=bk[i];
c[i^1]=0;
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("x.in","r",stdin);
#endif
init();
link();
Dinic();
printf("%d\n",ans);
change(2);
Dinic();
printf("%d\n",ans);
change(3);
Dinic();
printf("%d\n",ans);
return 0;
}