最小费用最大流改动下,将本来的正边改成负边 就成了 最大费用最大流。
然后构图,自己慢慢构。
拆点,建立流量为1 费用为权值的边。
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=2000,maxm=100000,inf=100000000;
struct Edge
{
Edge(){};
Edge(int a,int b,int c,int d){v=a;f=b;w=c;nxt=d;}
int v,f,w,nxt;
};
int Map[30][30];
int src,sink;
struct Edge e[maxm+10];
int g[maxn+10];
int nume;
queue<int >que;
int dist[maxn+10];
int prev[maxn+10],pree[maxn+10];
bool inQue[maxn+10];
void add(int u,int v,int f,int w)
{
e[++nume]=Edge(v,f,-w,g[u]);
g[u]=nume;
e[++nume]=Edge(u,0,w,g[v]);
g[v]=nume;
}
bool findPath()
{
while(!que.empty()) que.pop();
que.push(src);
int i;
for(i=1;i<=sink;i++) dist[i]=inf;
dist[src]=0;
memset(inQue,false,sizeof(inQue));
inQue[src]=true;
while(!que.empty()){
int u=que.front();
que.pop();
for(i=g[u] ; i ;i=e[i].nxt){
if(e[i].f>0&&dist[u]+e[i].w<dist[e[i].v]){
dist[e[i].v]=dist[u]+e[i].w;
prev[e[i].v]=u;
pree[e[i].v]=i;
if(!inQue[e[i].v]){
que.push(e[i].v);
inQue[e[i].v]=true;
}
}
}
inQue[u]=false;
}
if(dist[sink]<inf) return true;
return false;
}
int augment()
{
int u=sink;
int delta=inf;
while(u!=src){
if(e[pree[u]].f<delta) delta=e[pree[u]].f;
u=prev[u];
}
u=sink;
while(u!=src){
e[pree[u]].f-=delta;
e[pree[u]^1].f+=delta;
u=prev[u];
}
return dist[sink]*delta;
}
int maxcostflow()
{
int cur=0;
while(findPath()){
cur+=augment();
}
return cur;
}
int main()
{
int n;
int i,j;
while(scanf("%d",&n)!=EOF){
nume=1;
memset(g,0,sizeof(g));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&Map[i][j]);
src=1;sink=2*n*n;
for(i=0;i<n;i++)
for(j=0;j<n;j++){
if(i==0&&j==0){
add(src,src+n*n,2,0);
if(j+1<n) add(src+n*n,i*n+j+1+1,1,0);
if(i+1<n) add(src+n*n,(i+1)*n+j+1,1,0);
}
else if(i==n-1&&j==n-1) add(n*n,sink,2,0);
else{
add(i*n+j+1,i*n+j+n*n+1,1,Map[i][j]);
if(j+1<n) add(i*n+j+n*n+1,i*n+j+1+1,1,0);
if(i+1<n) add(i*n+j+n*n+1,(i+1)*n+j+1,1,0);
}
}
printf("%d\n",Map[0][0]+Map[n-1][n-1]-maxcostflow());
}
return 0;
}