费用流。。。。需要把一个点拆成两个点。。。这样不容易走重复。///
#include<stdio.h> #include<iostream> #include<queue> #include<string.h> #define INF 0x7fffffff using namespace std; int m,n,x,he[5100],vi[5100],pre[5100],dist[5100]; struct s { int ne,v,w,f; }st[210001]; void add(int ne,int v,int f,int w) { st[x].v=v;st[x].f=f;st[x].w=w; st[x].ne=he[ne];he[ne]=x++; st[x].v=ne;st[x].f=0;st[x].w=-w; st[x].ne=he[v];he[v]=x++; } queue<int> q; bool dfs(int qd,int t) { memset(vi,0,sizeof(vi)); memset(pre,-1,sizeof(pre)); int i; for(i=0;i<=t;i++) dist[i]=-INF; dist[0]=0; while(!q.empty()) q.pop(); q.push(0); vi[0]=1; while(!q.empty()) { int fr=q.front(); q.pop(); vi[fr]=0;//此处不能忘 for(i=he[fr];i!=-1;i=st[i].ne) { int v=st[i].v; if(st[i].f>0&&dist[v]<dist[fr]+st[i].w) { dist[v]=dist[fr]+st[i].w; pre[v]=i; if(!vi[v]) { q.push(v); vi[v]=1; } } } } if(pre[t]==-1) return false; else return true; } void fy(int qd,int t) { int sum=0; while(dfs(qd,t)) { // cout<<"dist "<<dist[t]<<endl; sum+=dist[t]; int k=pre[t]; while(k!=-1) { st[k].f--; st[k^1].f++;//chichu k=pre[st[k^1].v]; } } printf("%d\n",sum); } int main() { int a; scanf("%d",&a); while(a--) { scanf("%d%d",&m,&n); int i,j,b; memset(he,-1,sizeof(he)); x=0; int t=(m*n-1)*2+1; add(0,1,2,0); add(t-1,t,2,0); for(i=0;i<m;i++) for(j=0;j<n;j++) { scanf("%d",&b); if(i!=m-1) add((i*n+j)*2+1,((i+1)*n+j)*2,1,0); if(j!=n-1) add((i*n+j)*2+1,(i*n+j+1)*2,1,0); if(!(i==0&&j==0)&&!(i==m-1&&j==n-1)) add((i*n+j)*2,(i*n+j)*2+1,1,b); } fy(0,t); } return 0; }