网络流24题的坑还没填完,真的要TJ?
题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大。
啊简单的费用流。每个点i拆成i和i',连一条容量为1的边价值为点权,再连一条容量inf的边价值为0来让这个点能被经过,然后S连(1,1)容量k价值0,i'和右、下的点连容量inf价值0的边,(n,n)'连T容量inf价值0,跑最大费用最大流。
MDZZ看见n50我就开50,这是矩阵啊喂
#include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int inf=1000000000,maxn=5100; struct poi{int dis,pos;}; struct zs{int too,pre,c,cf,v,f;}e[1000010]; priority_queue<poi>q; bool operator <(poi a,poi b){return a.dis<b.dis;}; int n,k,z,tot,sum,ans; int last[maxn],dist[maxn],pre[maxn]; bool v[maxn]; void read(int &k) { k=0;int f=1;char c=getchar(); while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar(); k*=f; } void add(int x,int y,int c,int v) { e[++tot].too=y;e[tot].c=e[tot].cf=c;e[tot].v=v; e[tot].pre=last[x];last[x]=tot; e[++tot].too=x;e[tot].v=-v; e[tot].pre=last[y];last[y]=tot; } void spfa(int x) { for(int i=0;i<=sum;i++)pre[i]=-1,dist[i]=-inf,v[i]=0; dist[x]=0;v[x]=1;q.push((poi){0,x}); while(!q.empty()) { int now=q.top().pos;q.pop(); for(int i=last[now],too=e[i].too;i;i=e[i].pre,too=e[i].too) if(e[i].cf) if(dist[too]<dist[now]+e[i].v) { dist[too]=dist[now]+e[i].v;pre[too]=i; if(!v[too])v[too]=1,q.push((poi){dist[too],too}); } v[now]=0; } } void ford(int s,int t) { spfa(s); while(pre[t]!=-1) { int mincf=inf; for(int i=pre[t];i!=-1;i=pre[e[i^1].too]) mincf=min(mincf,e[i].cf); ans+=dist[t]*mincf; for(int i=pre[t];i!=-1;i=pre[e[i^1].too]) { e[i].f+=mincf;e[i^1].f=-e[i].f; e[i].cf-=mincf;e[i^1].cf+=mincf; } spfa(s); } } int num(int x,int y){return (x-1)*n+y;} int main() { tot=1; read(n);read(k);sum=2*n*n+1; add(0,1,k,0);add(2*n*n,sum,k,0); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { read(z); add(num(i,j),num(i,j)+n*n,1,z); add(num(i,j),num(i,j)+n*n,inf,0); if(i!=n)add(num(i,j)+n*n,num(i+1,j),inf,0); if(j!=n)add(num(i,j)+n*n,num(i,j+1),inf,0); } ford(0,sum); printf("%d ",ans); }