传送门
写在前面:DP后的网络流
思路:主要是建图,下图为样例
(灵魂画师上线ing)
中间是类似于数字三角形的,但是每个点要拆成两个,一个管入,一个管出,中间连边流量为1,防止重叠路径
注意:巧妙地记录点可以使建图简化
代码:
#include<bits/stdc++.h>
using namespace std;
int s,t,n,m,k,cnt,tot=1,ans;
int first[20000],dis[20000],up[20000];
queue<int> q;
bool vis[20000];
struct node
{
int data,x,y;
}a[32][62];
struct edge
{
int u,v,w,cost,next;
}e[40000];
void add(int x,int y,int z,int c)
{
e[++tot].u=x;
e[tot].v=y;
e[tot].w=z;
e[tot].cost=c;
e[tot].next=first[x];
first[x]=tot;
}
bool spfa()
{
memset(dis,63,sizeof(dis));
memset(up,0,sizeof(up));
dis[s]=0;vis[s]=1;
q.push(s);
while (!q.empty())
{
int k=q.front();
q.pop();
vis[k]=0;
for (int i=first[k];i;i=e[i].next)
if (e[i].w&&dis[e[i].v]>dis[k]+e[i].cost)
{
dis[e[i].v]=dis[k]+e[i].cost;
up[e[i].v]=i;
if (!vis[e[i].v]) vis[e[i].v]=1,q.push(e[i].v);
}
}
return dis[t]<0x7ffff;
}
void flow()
{
int minn=0x7fffffff;
for (int i=up[t];i;i=up[e[i].u])
minn=min(minn,e[i].w);
for (int i=up[t];i;i=up[e[i].u])
e[i].w-=minn,
e[i^1].w+=minn,
ans+=minn*e[i].cost;
}
main()
{
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++)
for (int j=1;j<=m+i-1;j++)
{
scanf("%d",&a[i][j].data);
a[i][j].data=-a[i][j].data;
a[i][j].x=++cnt;
a[i][j].y=++cnt;
add(cnt-1,cnt,1,0);
add(cnt,cnt-1,0,0);
}
s=(2*m+n-1)*n+1;
t=(2*m+n-1)*n+2;
for (int i=1;i<=m;i++)
add(s,a[1][i].x,1,a[1][i].data),
add(a[1][i].x,s,0,-a[1][i].data);
for (int i=1;i<n;i++)
for (int j=1;j<=m+i-1;j++)
add(a[i][j].y,a[i+1][j].x,1,a[i+1][j].data),
add(a[i+1][j].x,a[i][j].y,0,-a[i+1][j].data),
add(a[i][j].y,a[i+1][j+1].x,1,a[i+1][j+1].data),
add(a[i+1][j+1].x,a[i][j].y,0,-a[i+1][j+1].data);
for (int i=1;i<=m+n-1;i++)
add(a[n][i].y,t,1,0),
add(t,a[n][i].y,0,0);
while (k--&&spfa()) flow();
printf("%d",-ans);
}