poj3422 卡卡的矩阵旅行(费用流)

题意

做过过河卒(一取方格数)、传纸条(二取方格数),我们这里来安利K取方格数。
也就是给出一个方阵,大小为 n × n
每一个格子都有一个权值。
我们需要从左上角到右下角取 n 条路径。每一条路径都会取掉当前方格内的数。多条路径通过同一个位置的话,这个位置的数只取一次。
要求最大化k条路径取到的数之和。

题解

由于每一个点的数只能被取一次,但是可以被走过多次。
所以我们需要拆点。
把每一个点拆成一个入点一个出点。先连一条容量为1,费用为权值的边;再连一条容量为k-1,费用为0的边。代表第一次经过能有权值,之后经过没有权值。
然后对于任意一个点都从它的出点连向它右边点和下面点的入点一条容量为k,费用为0的边。
然后以左上角点的入点为源点;以右下角点的出点为汇点做最大费用最大流就行了。

code

#include <iostream> 
#include <cstdio> 
#include <fstream> 
#include <algorithm> 
#include <cmath> 
#include <deque> 
#include <vector> 
#include <queue> 
#include <string> 
#include <cstring> 
#include <map> 
#include <stack> 
#include <set> 
using namespace std;
inline int read(){
    int num=0;char c=' ';bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
        if(c=='-')
            flag=false;
    for(;c>='0'&&c<='9';num=(num<<3)+(num<<1)+c-48,c=getchar());
    return flag ? num : -num;
}
namespace graph{
    const int maxn=6000;
    struct node{
        int y,val,next,cost;
    }a[maxn<<4];
    int head[maxn],top=0;
    void insert(int x,int y,int v,int c){
        a[top].y=y;
        a[top].val=v;
        a[top].cost=c;
        a[top].next=head[x];
        head[x]=top++;
    }
    int n,k,map[60][60],s,t;
    int num(int i,int j,int k){
        return (i-1)*n+j+k*n*n;
    }
    //获取点号,i和j代表坐标,k=0是入点,k=1是出点
    void init(){
        memset(head,-1,sizeof head);
        n=read();k=read();
        s=1;t=2*n*n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                map[i][j]=read();
                insert(num(i,j,0) , num(i,j,1) , 1 , map[i][j]);
                insert(num(i,j,1) , num(i,j,0) , 0 ,-map[i][j]);
                insert(num(i,j,0) , num(i,j,1) ,k-1, 0 );
                insert(num(i,j,1) , num(i,j,0) , 0 , 0 );
                if(i<n){
                    insert(num(i,j,1) , num(i+1,j,0) , k , 0 );
                    insert(num(i+1,j,0) , num(i,j,1) , 0 , 0 );
                }
                if(j<n){
                    insert(num(i,j,1) , num(i,j+1,0) , k , 0 );
                    insert(num(i,j+1,0) , num(i,j,1) , 0 , 0 );
                }
            }
    }
}using namespace graph;

namespace max_flow_max_cost{
    int maxflow=0,maxcost=0;
    int dis[maxn],pre[maxn],flow[maxn];
    bool vis[maxn];
    bool spfa(){
        memset(dis,0xcf,sizeof dis);
        memset(vis,0,sizeof vis);
        queue<int>q;
        q.push(s);
        dis[s]=0;
        vis[s]=1;
        flow[s]=0x7fffffff;
        while(q.size()){
            int u=q.front();
            q.pop();
            vis[u]=0;
            for(int i=head[u];i+1;i=a[i].next){
                if(!a[i].val)continue;
                int v=a[i].y;
                if(dis[v]<dis[u]+a[i].cost){
                    flow[v]=min(flow[u],a[i].val);
                    dis[v]=dis[u]+a[i].cost;
                    pre[v]=i;
                    if(!vis[v]){
                        vis[v]=true;
                        q.push(v);
                    }
                }
            }
        }
        if(dis[t]==0xcfcfcfcf)return false;
        return true;
    }
    void updata(){
        int x=t;
        while(x!=s){
            int i=pre[x];
            a[i].val-=flow[t];
            a[i^1].val+=flow[t];
            x=a[i^1].y;
        }
        maxflow+=flow[t];
        maxcost+=dis[t]*flow[t];
    }
}using namespace max_flow_max_cost;

int main(){
    init();
    while(spfa())updata();
    printf("%d\n",maxcost);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39670434/article/details/81145717
今日推荐