Processing math: 100%

洛谷P2045 方格取数加强版 最小费用流

比较简单的费用流.    

我们发现题目中有几个性质:  

1. 总共走 k 次.  

2. 每个格子可以无限经过.  

3. 每个格子最多只能贡献 1 次.  

根据上述条件,我们就将每个格子进行拆点,拆成入点和出点.   

入点向出点连一条 (1,a[i][j]) 的边,表示贡献.   

入点向出点连一条 (+,0) 的边,表示只是经过,但不贡献.  

然后对于相邻点的话就从一个点的出点连到另一个点的入点就行了.     

再设超级源点,超级汇点就行了.   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn=10000+3;
const int INF=100000+123;
int s,t,n;
struct Edge{
    int from,to,cap,cost;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),cost(f){}
};
struct MCMF{
    vector<Edge>edges;
    vector<int>G[maxn];
    int d[maxn],inq[maxn],a[maxn],flow2[maxn];
    queue<int>Q;
    ll ans=0;
    int flow=0;
    void addedge(int u,int v,int c,int f){
        edges.push_back(Edge(u,v,c,f));    //正向弧
        edges.push_back(Edge(v,u,0,-f));   //反向弧
        int m=edges.size();
        G[u].push_back(m-2);
        G[v].push_back(m-1);
    }
    int SPFA(){
        for(int i=0;i<=n*2;++i)d[i]=INF,flow2[i]=INF;
        memset(inq,0,sizeof(inq));
        int f=INF;
        d[s]=0,inq[s]=1;Q.push(s);
        while(!Q.empty()){
            int u=Q.front();Q.pop();inq[u]=0;      
            int sz=G[u].size();
            for(int i=0;i<sz;++i){
                  Edge e=edges[G[u][i]];
                  if(e.cap>0&&d[e.to]>d[u]+e.cost){
                      a[e.to]=G[u][i];
                      d[e.to]=d[u]+e.cost;
                      flow2[e.to]=min(flow2[u],e.cap);
                      if(!inq[e.to]){inq[e.to]=1;Q.push(e.to);}
                  }
            }
             
        }
        if(d[t]==INF||d[t]==0)return 0;
        f=flow2[t];
        flow+=f;
        int u=edges[a[t]].from;
        
        edges[a[t]].cap-=f;
        edges[a[t]^1].cap+=f;
        while(u!=s){
            edges[a[u]].cap-=f;
            edges[a[u]^1].cap+=f;
            u=edges[a[u]].from;
            
        }
        ans+=(ll)(d[t])*(-1);
        return 1;
    }
    ll maxflow(){
        while(SPFA());
        return ans;
    }
};
int main(){
    int siz,k,cnt=0;
    MCMF op;
    scanf("%d%d",&siz,&k);
    n=siz*siz;
    for(int i=1;i<=siz;++i)
        for(int j=1;j<=siz;++j){
             int c;scanf("%d",&c); 
             ++cnt;
             op.addedge(cnt,cnt+1,1,-c);
             op.addedge(cnt,cnt+1,INF,0);
             ++cnt;
        }
    t=cnt;
    cnt=0;
    for(int i=1;i<=siz;++i)
        for(int j=1;j<=siz;++j){
            cnt+=2;
            if(i+1<=siz)op.addedge(cnt,cnt+(siz*2-1),INF,0);
            if(j+1<=siz)op.addedge(cnt,cnt+1,INF,0);
        }
    s=0;
    op.addedge(s,1,k,0);
    printf("%lld",op.maxflow());
    return 0;
}

  

posted @   EM-LGH  阅读(129)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示