平面图中最小割向最短路的转化

周冬的《两极相通——浅析最大最小定理在信息学竞赛中的应用》把方法讲的很详细了。

几点:

1、把平面图G*中每一个面抽象成对偶图G*中的点。

2、平面图包含f个面,设边e分割fi, fj,则连边(fi, fj)。

3、关于如何区分源点和汇点。可以先连接s和t,得到一个附加面。如下图s->4->7->t->s,s*放到附加面中,t*放到无边界的面中,加以区分。

4、建好图后要把(s*, t*)这条边删掉。

5、G的面数等于G*的点数,G*的点数等于G的面数

6、G与G*边数相同 G*中的环对应G中的割一一对应

如图:

 

hdu 3780

题意是求最小割。直接套网络流模板会TLE。转换成最短路模型然后用dijkstra求解就行,不过dijkstra要优先队列优化。

得到的最短路模型中,点数最多为(n - 1)*n*2 - n*n + 2,边数最多为(n - 1)*n*2*2,注意别MLE;

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%lld\n", x)
#define Read()  freopen("data.in", "r", stdin)
#define Write() freopen("data.out", "w", stdout);

typedef long long LL;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int inf = 0x1F1F1F1F;

using namespace std;

const int N = 410;

int mp[N][N];

class node {
public:
    int to;
    int val;
    int next;
}g[N*N<<2];

class pnode {
public:
    int num;
    int len;
    pnode() {};
    pnode(int a, int b) : num(a), len(b) {}
    bool operator < (const pnode p) const {
        return this->len > p.len;
    }
};

priority_queue<pnode> q;

int head[N*N + 10], t;
int dis[N*N + 10];
bool vis[N*N + 10];

int S, T, n;

void init() {
    memset(head, -1, sizeof(head));
    t = 0;
}

void add(int u, int v, int c) {
    g[t].to = v; g[t].val = c; g[t].next = head[u]; head[u] = t++;
    g[t].to = u; g[t].val = c; g[t].next = head[v]; head[v] = t++;
}

int dijkstra(int s, int t) {
    while(!q.empty())   q.pop();
    q.push(pnode(s, 0));

    int i, v;
    pnode u;

    for(i = 0; i <= t; ++i) {
        dis[i] = inf;
        vis[i] = false;
    }
    dis[0] = 0;

    while(!q.empty()) {
        u = q.top(); q.pop();
        if(u.len != dis[u.num]) continue;
        if(vis[u.num])  continue;
        vis[u.num] = true;

        for(i = head[u.num]; i != -1; i = g[i].next) {
            v = g[i].to;
            if(dis[v] > u.len + g[i].val) {
                dis[v] = u.len + g[i].val;
                q.push(pnode(v, dis[v]));
            }
        }
    }
    return dis[t];
}

int main() {
    //Read();

    int TT, n, i, j, u, S, T;
    scanf("%d", &TT);
    while(TT--) {
        scanf("%d", &n);
        for(i = 1; i <= n; ++i) {
            for(j = 1; j <= n; ++j) {
                scanf("%d", &mp[i][j]);
            }
        }
        init();
        S = 0; T = (n - 1)*(n - 1) + 1;
        for(i = 1; i <= n - 1; ++i) {
            for(j = 1; j <= n - 1; ++j) {
                u = (i - 1)*(n - 1) + j;
                if(i == 1)  add(S, u, mp[i][j]);
                if(j == 1)  add(u, T, mp[i][j]);
                if(i == n - 1)  add(u, T, mp[i + 1][j]);
                if(j == n - 1)  add(S, u, mp[i][j + 1]);
                if(i < n - 1)   add(u, u + n - 1, mp[i + 1][j]);
                if(j < n - 1)   add(u, u + 1, mp[i][j + 1]);
            }
        }
        printf("%d\n", dijkstra(S, T));
    }
    return 0;
}
View Code

 

 

 

 

 

 

posted @ 2013-06-01 11:39  AC_Von  阅读(1454)  评论(0编辑  收藏  举报