POJ 3422 Kaka's Matrix Travels | 最小费用最大流

题目:

给个n*n的带正权矩阵,k次从(1,1)走到(n,n),每个格子的权值只能获得一次,每次只能向右或下走

问获得最大权值


题解:

求最大权值可以把权值变成负的求最小

然后考虑怎么约束每个格子的权值,

把格子拆成两个点,连两条边:一条容量为1,花费为-权值,一条容量为INF,花费为0

S到第一个格子,连容量为k,最后一个格子的二号点到T,容量为k

这样就可以限制每个点只有走一次的时候能获得权值,

跑最小费用最大流

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 5010
#define INF 1000000
using namespace std;
int ecnt=1,vis[N],dist[N],n,m,S,T,ans,head[N],k,w[N][N];
deque <int> q;
inline int get(int x,int y)
{
    return n*(x-1)+y;
}
struct adj
{
    int nxt,v,w,c;
}e[N*N];
inline void add(int u,int v,int w,int c)
{
    e[++ecnt].v=v,e[ecnt].w=w,e[ecnt].c=c,e[ecnt].nxt=head[u],head[u]=ecnt;
    e[++ecnt].v=u,e[ecnt].w=0,e[ecnt].c=-c,e[ecnt].nxt=head[v],head[v]=ecnt;
}
inline int spfa(int s,int t)
{
    int v;
    memset(vis,0,sizeof(vis));
    for (int i=s;i<=t;i++) dist[i]=INF;
    dist[t]=0,vis[t]=1;
    q.push_back(t);
    while (!q.empty())
    {
    int u=q.front();q.pop_front();
    for (int i=head[u];i;i=e[i].nxt)
        if (e[i^1].w>0 && dist[v=e[i].v]>dist[u]-e[i].c)
        {
        dist[v]=dist[u]-e[i].c;
        if (!vis[v])
        {
            vis[v]=1;
            if (!q.empty() && dist[v]<dist[q.front()])
            q.push_front(v);
            else
            q.push_back(v);
        }
        }
    vis[u]=0;
    }
    return dist[s]<INF;
}
inline int dfs(int x,int flow)
{
    //   puts("DFS");
    if (x==T)
    return vis[T]=1,flow;
    int used=0,tmp,v;
    vis[x]=1;
    for (int i=head[x];i;i=e[i].nxt)
    if (!vis[v=e[i].v] && e[i].w>0 && dist[x]-e[i].c==dist[v])
    {
        tmp=dfs(v,min(e[i].w,flow-used));
        if (tmp>0)
        ans+=tmp*e[i].c,e[i].w-=tmp,e[i^1].w+=tmp,used+=tmp;
        if (used==flow) break;
    }
    return used;
}
inline int CostFlow()
{
    int Flow=0;
    while (spfa(S,T))
    {
    vis[T]=1;
    while (vis[T])
    {
        memset(vis,0,sizeof(vis));
        Flow+=dfs(S,INF);
    }
    }
    return Flow;
}
int main()
{
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
	for (int j=1;j<=n;j++)
	    scanf("%d",&w[i][j]);
    for (int i=1;i<=n;i++)
	for (int j=1;j<=n;j++)
	{
	    int num=get(i,j);
	    add(num,num+n*n,1,-w[i][j]);
	    add(num,num+n*n,k-1,0);
	    if (i<n) add(n*n+num,get(i+1,j),k,0);
	    if (j<n) add(n*n+num,get(i,j+1),k,0);
	}
    S=0,T=n*n+n*n+1;
    add(S,1,k,0);
    add(n*n+get(n,n),T,k,0);
    CostFlow();
    printf("%d",-ans);
    return 0;
}

 

posted @ 2017-12-02 15:48  MSPqwq  阅读(122)  评论(0编辑  收藏  举报