ZOJ 3308 最小費用最大流

不管是最大流還是費用流,模板一般都不會出什麼問題,一般錯就錯在建圖……

這也是一道裸的套費用流模板的題,不得不說,費用流代碼量真是大,初始化什麼的完成基本就快100行代碼了。

費用流的基本思想是多次最短路,所以在MCMF函數裏會看到while(spfa(st, ed))這麼個東西。


先貼代碼後分析:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 555;
const int maxm = 55555;
const int inf = 1 << 30;
struct node
{
       int to, next, c, f;
}edge[maxm * 10];

int head[maxn];
int src, des, r, c, n, k, sm;
int dis[maxn], load[maxn], p[maxn];
bool vis[maxn][maxn];
bool flag[maxn];
int a[20][20];
int xx[8] = {1, 2, 2, 1, -1, -2, -2, -1};
int yy[8] = {-2, -1, 1, 2, -2, -1, 1, 2};

bool isok(int x, int y)
{
     return (x >= 0 && x < r && y >= 0 && y < c);
}

void add_edge(int u, int v, int c, int f)
{
     edge[sm].to = v;
     edge[sm].c = c;
     edge[sm].f = f;
     edge[sm].next = head[u];
     head[u] = sm ++;
     edge[sm].to = u;
     edge[sm].c = 0;
     edge[sm].f = -f;
     edge[sm].next = head[v];
     head[v] = sm ++;
}

bool spfa(int st, int ed)
{
     int que[maxn * 10], qout, qin;
     memset(flag, false, sizeof(flag));
     memset(load, -1, sizeof(load));
     memset(p, -1, sizeof(p));
     for(int i = 0; i <= des + 1; i ++)
             dis[i] = inf;
     qin = qout = 0;
     que[qin ++] = st;
     dis[st] = 0;
     flag[st] = true;
     while(qin != qout)
     {
               int e = que[qout ++];
               flag[e]  =false;
               for(int i = head[e]; i != -1; i = edge[i].next)
               {
                       if(edge[i].c)
                       {
                                    int ne = edge[i].to;
                                    if(dis[ne] - dis[e] > edge[i].f)
                                    {
                                               dis[ne] = edge[i].f + dis[e];
                                               p[ne] = e;
                                               load[ne] = i;
                                               if(!flag[ne])
                                               {
                                                            flag[ne] = true;
                                                            que[qin ++] = ne;
                                               }
                                    }
                       }
               }
     }
     if(dis[ed] == inf)
                return false;
     return true;
}

int MCMF(int st, int ed)
{
    int u, mn;
    int ans_f = 0, ans_c = 0;
    while(spfa(st, ed))
    { 
                   u = ed;
                   mn = inf;
                   while(p[u] != -1)
                   {
                              mn = min(edge[load[u]].c, mn);
                              u = p[u];
                   }
                   u = ed;
                   while(p[u] != -1)
                   {
                              edge[load[u]].c -= mn;
                              edge[load[u]^1].c += mn;
                              u = p[u];
                   }
                   ans_c += dis[ed] * mn;
                   ans_f += mn;
    }
    if(ans_f != k)
             return -1;
    return ans_c;
}

int main()
{
    while(scanf("%d%d%d%d", &r, &c, &n, &k) != EOF)
    {
                   int i, j, type;
                   for(i = 0; i < r; i ++)
                         for(j = 0; j < c; j ++)
                               scanf("%d", &a[i][j]);
                   memset(head, -1, sizeof(head));
                   memset(vis, 0, sizeof(vis));
                   sm = 0;
                   src = r * c + 1, des = r * c + 2;
                   add_edge(src, r * c, k, 0);
                   for(int u = 0; u < n; u ++)
                   {
                         scanf("%d%d%d", &type, &i, &j);
                         i --, j --;
                         int tmp = i * c + j;
                         add_edge(r * c, tmp, 1, 0);
                         for(int no = 0; no < 8; no ++)
                         {
                                       int px = xx[no] + i;
                                       int py = yy[no] + j;
                                       if(isok(px, py))
                                       {
                                              int tmp2 = px * c + py;
                                              if(type == 1)
                                                           add_edge(tmp, tmp2, 1, a[i][j] * a[px][py]);
                                              if(type == 2)
                                                           add_edge(tmp, tmp2, 1, a[i][j] + a[px][py]);
                                              if(type == 3)
                                                           add_edge(tmp, tmp2, 1, max(a[i][j], a[px][py]));
                                              vis[px][py] = true;
                                       }
                         }
                   }
                   for(i = 0; i < r * c; i ++)
                         if(vis[i / c][i % c])
                                           add_edge(i, des, 1, 0); 
                   int ans = MCMF(src, des);
                   printf("%d\n", ans);
    }
}


一開始一直沒調通,後來發現是這個地方出了問題。

for(i = 0; i < r * c; i ++)
       if(vis[i / c][i % c])
                add_edge(i, des, 1, 0); 


之前一直沒調出來的程序裏是沒有if判斷的,結果就一直不對。後來突然想到,如果對每個點都向超級終點連邊,而且容量是1,費用是0的話,最後就會發生ans = 0的情況,因爲好多不相關的點都被連了進去,他們本來的費用是0。


明天繼續網絡流 + 數據結構。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章