@bzoj - 2668 @ [cqoi2012] переключения частей


@описание@

A N строк и т столбцы реверса, вы можете обмениваться каждые две соседние решеток (см до общих ребер смежной или общей вершины) куска, конечная цель достигается состояние. Требования к-я строка J-го столбца сетки могут участвовать только ми, J раза обмена.

Входные
данные Первая строка содержит два целых числа п, т (1 <= п , т <= 20). Начальное состояние п линий, каждый из которых содержит поведение строки символов м 01, где 0 представляют черные части, часть 1 представляет собой белым. Следующее поведенческий таргетинг состояние п тот же формат , как исходное состояние. Каждый из п строк т провести строку чисел от 0 до 9, содержащая, для каждой сетки представляет собой максимальное число участвующих обменов.

Выходной
линейный выход только минимальное общее количество обмена. Если нет никакого решения, выход из -1.

Пример ввода
3 3
110
000
001
000
110
100
222
222
222
Пример вывода
4

@решение@

Если цветные кусочки путем замены сначала перемещаются в конечном состоянии, то белые фигуры будут , соответственно , становится целевым состоянием.
Это означает , что мы можем быть черная пешка считается «пешками», белой пешкой как «вакансия», обмен как «переместить кусок к соседнему пространству ребенку» (как это невозможно обмен между одинаковыми цветовыми штуками ).

Если ситуация является отправной сеткой р частей, части также прекратили дело, то мы можем рассматривать как место не пешка.
Почему? Если перемещается в р штук х, у , а другой перемещается к р штук. Это эквивалентно не куска р, у перемещается непосредственно в й.
Приведенные выше идеи на самом деле говорит нам , что между куски и кусочки, не блокируются другим (блокировка , если вы можете заменить эквивалент , как указано выше).

Таким образом, начиная со случаем , когда нагрузочные куски без необходимости перехода к р частям концевых частей инициировали случай без камней д.
Это очень похоже на двудольный граф задачи согласования, так что мы можем думать о сетевом потоке.

Но модель сетевого потока, не существует хороший способ ограничить «число обменов.»
Если сетка начиная в случае с корпусом терминала, то число других частей в решетке а = числа сетки. Это становится все более очевидным.
Таким образом , мы имеем наиболее \ (\ lfloor \ гидроразрыва {m_ {I, J}} {2} \ rfloor \) й частей через сетку, сетка может быть удалена таким образом , что точки, способность к краю \ (\ lfloor \ {{Я m_Low FRAC, J} {2}} \ rfloor \) .
Различные, аналогичные приведенным выше , могут быть выведены вверх \ (\ lceil \ FRAC m_Low {{I, J} {2}} \ rceil \) (шт содержит начало сдвига из последнюю часть и двигаться в) а после этого кусок пледа.

Таким образом , построена на фиг более очевидна:
начальное состояние и целевое состояние одинаково (I, J), точка разделения х -> х», промежуточная емкость связи \ (\ lfloor \ гидроразрыва {M_ {I, J}} {2 } \ rfloor \) сторона.
Есть штук в исходное состояние, целевое состояние без камней (I, J), точка разделения х -> х», промежуточной емкости связи \ (\ lceil \ гидроразрыва {M_ {I, J}} {2} \ rceil \) кромка, соединено с емкостью х 1 сек стороны источник.
Нет частей в исходное состояние, целевое состояние с куском (I, J), точка разделения х -> х», промежуточной емкости связи \ (\ lceil \ гидроразрыва {M_ {I, J}} {2} \ rceil \) края; х «т подключены к раковине стороны емкости 1.
Примыкающие две клетки, и даже между мощностью двунаправленного края инф.

Бегите, чтобы увидеть, если полный поток максимального потока.

@accepted код @

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 20;
const int INF = (1<<30);
const int MAXV = 2*MAXN*MAXN;
const int MAXE = 45*MAXV + 5;
const int dx[] = {0, 1, -1};
const int dy[] = {1, -1, 0};
struct FlowGraph{
    struct edge{
        int to, cap, flow, cost;
        edge *nxt, *rev;
    }edges[MAXE + 5], *adj[MAXV + 5], *cur[MAXV + 5], *ecnt;
    FlowGraph() {ecnt = &edges[0];}
    int s, t, cost;
    void addedge(int u, int v, int c, int w) {
        edge *p = (++ecnt), *q = (++ecnt);
        p->to = v, p->cap = c, p->flow = 0, p->cost = w;
        p->nxt = adj[u], adj[u] = p;
        q->to = u, q->cap = 0, q->flow = 0, q->cost = -w;
        q->nxt = adj[v], adj[v] = q;
        p->rev = q, q->rev = p;
    }
    int f[MAXV + 5], hp[MAXV + 5];
    void update(int x, int k) {
        f[x] = k;
        while( x ) {
            hp[x] = x;
            if( (x<<1) <= t && f[hp[x]] > f[hp[x<<1]] )
                hp[x] = hp[x<<1];
            if( (x<<1|1) <= t && f[hp[x]] > f[hp[x<<1|1]])
                hp[x] = hp[x<<1|1];
            x >>= 1;
        }
    }
    int d[MAXV + 5], h[MAXV + 5];
    bool relabel() {
        for(int i=1;i<=t;i++)
            h[i] += d[i], d[i] = f[i] = INF, hp[i] = i, cur[i] = adj[i];
        d[s] = 0; update(s, 0);
        while( f[hp[1]] != INF ) {
            int x = hp[1]; update(x, INF);
            for(edge *p=adj[x];p;p=p->nxt) {
                int w = p->cost + h[x] - h[p->to];
                if( d[x] + w < d[p->to] && p->cap > p->flow ) {
                    d[p->to] = d[x] + w;
                    update(p->to, d[p->to]);
                }
            }
        }
        return !(d[t] == INF);
    }
    bool vis[MAXV + 5];
    int aug(int x, int tot) {
        if( x == t ) return tot;
        int sum = 0; vis[x] = true;
        for(edge *&p=cur[x];p;p=p->nxt) {
            int w = p->cost + h[x] - h[p->to];
            if( d[x] + w == d[p->to] && p->cap > p->flow && !vis[p->to] ) {
                int del = aug(p->to, min(tot - sum, p->cap - p->flow));
                p->flow += del, p->rev->flow -= del, sum += del;
                if( sum == tot ) break;
            }
        }
        vis[x] = false;
        return sum;
    }
    int min_cost_max_flow(int _s, int _t) {
        s = _s, t = _t, cost = 0; int flow = 0;
        while( relabel() ) {
            int del = aug(s, INF);
            flow += del, cost += del*(d[t] + h[t]);
        }
        return flow;
    }
}G;
int n, m;
int A[MAXN + 5][MAXN + 5], B[MAXN + 5][MAXN + 5];
int C[MAXN + 5][MAXN + 5], id[MAXN + 5][MAXN + 5];
char str[MAXN + 5];
int main() {
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n;i++) {
        scanf("%s", str + 1);
        for(int j=1;j<=m;j++)
            A[i][j] = str[j] - '0';
    }
    for(int i=1;i<=n;i++) {
        scanf("%s", str + 1);
        for(int j=1;j<=m;j++)
            B[i][j] = str[j] - '0';
    }
    for(int i=1;i<=n;i++) {
        scanf("%s", str + 1);
        for(int j=1;j<=m;j++)
            C[i][j] = str[j] - '0';
    }
    int cnt = 0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            id[i][j] = (++cnt);
    int s = 2*cnt + 1, t = 2*cnt + 2, tot1 = 0, tot2 = 0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) {
            if( A[i][j] == B[i][j] )
                G.addedge(id[i][j], id[i][j] + cnt, C[i][j] / 2, 0);
            else if( A[i][j] == 1 && B[i][j] == 0 ) {
                G.addedge(s, id[i][j], 1, 0); tot1++;
                G.addedge(id[i][j], id[i][j] + cnt, (C[i][j] + 1) / 2, 0);
            }
            else if( A[i][j] == 0 && B[i][j] == 1 ) {
                G.addedge(id[i][j] + cnt, t, 1, 0); tot2++;
                G.addedge(id[i][j], id[i][j] + cnt, (C[i][j] + 1) / 2, 0);
            }
            for(int k=0;k<3;k++)
                for(int l=0;l<3;l++) {
                    if( dx[k] == 0 && dy[l] == 0 ) continue;
                    int x = i + dx[k], y = j + dy[l];
                    if( 1 <= x && x <= n && 1 <= y && y <= m )
                        G.addedge(id[i][j] + cnt, id[x][y], INF, 1);
                }
        }
    if( tot1 == tot2 && G.min_cost_max_flow(s, t) == tot1 )
        printf("%d\n", G.cost);
    else puts("-1");
}

@подробности@

Укажите два относительно ямы.
Первое , что восьмая Tonglian по краям, а не обычные четыре связи мы часто делаем.
Во - вторых, количество частей и начальное состояние не гарантирует , что то же самое конечное состояние.
На самом деле, мы, по существу, прочитать название внимательно прочитать проблемы могут быть решены

рекомендация

отwww.cnblogs.com/Tiw-Air-OAO/p/11416040.html