题意:给你一个N*N的矩阵,要求从起点(1,1)(往右或下方向)到终点(N,N)再从终点(往左或上)到起点,使一路上走过的点的权值和最大(走过的点可以再走,但是每个点的权值最多只能取一次)。
难度:2
题解:最大费用流。将矩阵上每个点拆成两个点Xi和Yi,从Xi向Yi连一条容量为1,费用为该点权值的负值的边,再连一条容量为1,费用为零的边。对于每个点i, 以及他有侧或下侧的点j(如果有的话)从Yi向Xj连一条容量为2,费用为零的边。新增一个附加源s和一个附加汇t,s向X(1,1)连一条容量为2,费用为零的边,Y(N,N)向t连一条容量为2,费用为零的边。求得的最小费用的负值就是对大费用。
难度:2
题解:最大费用流。将矩阵上每个点拆成两个点Xi和Yi,从Xi向Yi连一条容量为1,费用为该点权值的负值的边,再连一条容量为1,费用为零的边。对于每个点i, 以及他有侧或下侧的点j(如果有的话)从Yi向Xj连一条容量为2,费用为零的边。新增一个附加源s和一个附加汇t,s向X(1,1)连一条容量为2,费用为零的边,Y(N,N)向t连一条容量为2,费用为零的边。求得的最小费用的负值就是对大费用。
#include<iostream>
using namespace std;
const int maxm=(600*600*2+2)*4;
const int maxn=600*600*2+2;
const int INF=100000000;
int map[600][600];
inline int min(int x,int y){return x<y?x:y;}
typedef struct node
{
int v,flow,cost;
node *next;
node *rev();
}node;
node edge[maxm],*adj[maxn],*rec[maxn];
bool use[maxn];
int d[maxn],pre[maxn],q[10*maxm],len;
node inline *node::rev(){return edge+((this-edge)^1);}
inline void addedge(int u,int v,int flow,int cost)
{
edge[len].v=v;edge[len].flow=flow;edge[len].cost=cost;
edge[len].next=adj[u];adj[u]=&edge[len++];
}
inline void insert(int u,int v,int flow,int cost)
{
addedge(u,v,flow,cost);
addedge(v,u,0,-cost);
}
bool SPFA(int n,int s,int t)
{
int u,v,i,head=0,tail=0;q[tail++]=s;
node *p;
for(i=0;i<n;i++){d[i]=INF;use[i]=0;pre[i]=-1;}
d[s]=0;use[s]=1;
while(head<tail)
{
for(u=q[head++],use[u]=0,p=adj[u];p;p=p->next)
{
if(p->flow>0&&d[u]+p->cost<d[p->v])
{
d[p->v]=d[u]+p->cost;
pre[p->v]=u;rec[p->v]=p;
if(!use[p->v]){q[tail++]=p->v;use[p->v]=1;}
}
}
}
return d[t]==INF;
}
int mincostflow(int n,int s,int t)
{
int u,v,mincost=0,tmp;
while(!SPFA(n,s,t))
{
for(tmp=INF,v=t;v!=s;v=pre[v])tmp=min(tmp,rec[v]->flow);
for(mincost+=tmp*d[t],v=t;v!=s;v=pre[v]){rec[v]->flow-=tmp;rec[v]->rev()->flow+=tmp;}
}
return mincost;
}
int main()
{
int n,m,i,j,k,s,t;
while(scanf("%d",&n)!=EOF)
{
m=2;
for(i=0;i<n*n*2+2;i++)adj[i]=NULL;
len=0;s=n*n*2;t=s+1;
for(i=0;i<n;i++)for(j=0;j<n;j++)scanf("%d",&map[i][j]);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
k=i*n+j;
insert(k*2,k*2+1,1,-map[i][j]);
insert(k*2,k*2+1,m-1,0);
}
for(i=0;i<n;i++)
for(j=0;j<n-1;j++)
{
k=i*n+j;
insert(2*k+1,2*(k+1),m,0);
}
for(i=0;i<n-1;i++)
for(j=0;j<n;j++)
{
k=i*n+j;
insert(2*k+1,2*(k+n),m,0);
}
insert(s,0,2,0);
insert(n*n*2-1,t,2,0);
printf("%d\n",-mincostflow(t+1,s,t));
}
return 0;
}