网络流学习笔记2

强盗

听过讲解后1A…

在一定时间周期内有若干个强盗,可以在 [ai,bi) 内任一时刻(这个时刻是你钦定的)抢劫,获取ci的收益。每一个时刻最多干一个强盗,问挽回的最大收益。

由于可以钦定,那必然是让他们抢劫在尽可能多的不同时间内。于是想到二分图带权匹配。由于边数太多,而且时间总是以区间形式出现,不妨在时间上建一棵线段树,然后连边跑费用流。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 40005, MAXM = 5000005;
struct node {
    int to, next, f, c, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k, int l)
{
    //printf("%d--%d,%d-->%d\n", i, k, l, j);
    ++top, edge[top] = (node) {j, head[i], k, l, top+1}, head[i] = top;
    ++top, edge[top] = (node) {i, head[j], 0, -l, top-1},head[j] = top;
}

int vis[MAXN], dis[MAXN], S = 40001, T = 40002, n, m = 1<<13;
int pre[MAXN], pre_edge[MAXN];
const int inf = 23333333;
queue<int> que;

bool spfa()
{
    memset(vis, 0, sizeof vis);
    memset(pre, 0, sizeof pre);
    memset(dis, 127/3, sizeof dis);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop(); vis[tp] = 0;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (!edge[i].f || dis[edge[i].to] <= dis[tp] + edge[i].c) continue;
            dis[edge[i].to] = dis[tp] + edge[i].c;
            pre[edge[i].to] = tp, pre_edge[edge[i].to] = i;
            if (!vis[edge[i].to]) vis[edge[i].to] = 1, que.push(edge[i].to);
        }
    }
    return dis[T] <= inf;
}

int work(int &cost)
{
    int ans = inf;
    for (int i = T; i != S; i = pre[i]) ans = min(ans, edge[pre_edge[i]].f);
    for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].f -= ans, edge[edge[pre_edge[i]].neg].f += ans;
    cost += ans*dis[T];
    return ans;
}

int mcf(int &cost)
{
    int ans = 0;
    while (spfa()) ans += work(cost);
    return ans;
}

int main()
{
    for (int i = m; i <= m+m-1; i++) push(i, T, 1, 0);
    for (int i = m-1; i >= 1; i--) push(i, i*2, inf, 0), push(i, i*2+1, inf, 0);
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        int a, b, c; scanf("%d%d%d", &a, &b, &c); b--;
        for (a += m-1, b += m-1; a < b; a >>= 1, b >>= 1) {
            if (a&1) push(m+m+i, a++, inf, 0);
            if (!(b&1)) push(m+m+i, b--, inf, 0);
        }
        if (a == b) push(m+m+i, a, inf, 0);
        push(S, m+m+i, 1, -c);
    }
    int cost = 0; mcf(cost);
    cout << -cost << endl;
    return 0;
}

NOI2008 志愿者招募

貌似是simplex的裸题…但是simplex调了一会调不出来,于是只好看题解写费用流。

建图方法比(ji)较(qi)诡异…

按时刻拆点,每个时刻连向下一个时刻为流量下界为ai,费用为0的边,用于保证每天的要求;对于每一种志愿者 [li,ri],从ri+1li连流量为无穷,费用为ci的边,跑一遍最小费用可行流。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005, MAXM = 200000;
struct node {
    int to, next, f, c, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k, int l)
{
    //printf("%d--%d,%d-->%d\n", i, k, l, j);
    ++top, edge[top] = (node) {j, head[i], k, l, top+1}, head[i] = top;
    ++top, edge[top] = (node) {i, head[j], 0, -l, top-1}, head[j] = top;
}
int n, m;
int S = 1002, T = 1003;
const int inf = 23333333;

void push_lim(int i, int j, int low)
{
    push(S, j, low, 0);
    push(i, T, low, 0);
    push(i, j, inf, 0);
}

int vis[MAXN], dis[MAXN];
int pre[MAXN], pre_edge[MAXN];
queue<int> que;

bool spfa()
{
    memset(vis, 0, sizeof vis);
    memset(dis, 127/3, sizeof dis);
    memset(pre, 0, sizeof pre);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop(); vis[tp] = 0;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (edge[i].f == 0 || dis[edge[i].to] <= dis[tp] + edge[i].c) continue;
            dis[edge[i].to] = dis[tp] + edge[i].c;
            pre[edge[i].to] = tp;
            pre_edge[edge[i].to] = i;
            if (!vis[edge[i].to])
                vis[edge[i].to] = 1, que.push(edge[i].to);
        }
    }
    return dis[T] <= inf;
}

int work(int &cost)
{
    int ans = inf;
    for (int i = T; i != S; i = pre[i]) ans = min(ans, edge[pre_edge[i]].f);
    for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].f -= ans, edge[edge[pre_edge[i]].neg].f += ans;
    cost += dis[T] * ans;
    //cout << dis[T] << "--" << endl;
    //cin.get();
    return ans;
}

int mcf(int &cost)
{
    int ans = 0;
    while (spfa()) ans += work(cost);
    return ans;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        int u; scanf("%d", &u);
        push_lim(i, i+1, u);
    }
    for (int i = 1; i <= m; i++) {
        int s, t, c; scanf("%d%d%d", &s, &t, &c);
        push(t+1, s, inf, c);
    }
    int cost = 0;
    mcf(cost);
    cout << cost << endl;
    return 0;
}

luogu1231 教辅的组成

经典的拆点建图。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005, MAXM = 5000005;
struct node {
    int to, next, f, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k)
{
    //printf("%d--%d-->%d\n", i, k, j);
    ++top, edge[top] = (node) {j, head[i], k, top+1} , head[i] = top;
    ++top, edge[top] = (node) {i, head[j], 0, top-1} , head[j] = top;
}

int vis[MAXN], bfstime = 0;
int lev[MAXN], que[MAXM], l = 0, r = 0;
int n1,n2,n3, m1,m2, S = 50001, T = 50002;
const int inf = 23333333;

bool bfs()
{
    vis[S] = ++bfstime, lev[S] = 0, que[++r] = S;
    while (l != r) {
        int tp = que[++l];
        for (int i = head[tp]; i; i = edge[i].next) {
            if (vis[edge[i].to] == bfstime || edge[i].f == 0) continue;
            lev[edge[i].to] = lev[tp] + 1, vis[edge[i].to] = bfstime, que[++r] = edge[i].to;
        }
    }
    return vis[T] == bfstime;
}

int dfs(int nd, int maxf = inf)
{
    if (nd == T || maxf == 0) return maxf;
    int ans = 0, t;
    for (int i = head[nd]; i; i = edge[i].next) {
        if (edge[i].f == 0 || lev[edge[i].to] != lev[nd]+1) continue;
        t = dfs(edge[i].to, min(maxf, edge[i].f));
        ans += t, maxf -= t;
        edge[i].f -= t, edge[edge[i].neg].f += t;
    }
    return ans;
}

int dinic()
{
    int ans = 0;
    while (bfs()) ans += dfs(S);
    return ans;
}

int main()
{
    scanf("%d%d%d", &n1, &n2, &n3);
    scanf("%d", &m1);
    for (int i = 1; i <= n1; i++) push(10000+i, 20000+i, 1);
    for (int i = 1; i <= n2; i++) push(S, i, 1);
    for (int i = 1; i <= n3; i++) push(30000+i, T, 1);
    for (int i = 1; i <= m1; i++) {
        int u, v; scanf("%d%d", &u,&v);
        push(v, 10000+u, 1);
    }
    scanf("%d", &m2);
    for (int i = 1; i <= m2; i++) {
        int u, v; scanf("%d%d", &u, &v);
        push(u+20000, 30000+v, 1);
    }
    cout << dinic() << endl;
    return 0;
}

ZJOI2009 假期的宿舍

1A..
裸的二分图匹配,最大流就过了..

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 305, MAXM = 100005;

struct node {
    int to, next, f, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k)
{
    //printf("%d---%d-->%d\n", i, k, j);
    ++top, edge[top] = (node){ j, head[i], k, top+1}, head[i] = top;
    ++top, edge[top] = (node){ i, head[j], 0, top-1}, head[j] = top;
}

int lev[MAXN], vis[MAXN], bfstime = 0;
queue<int> que;
int S = 301, T = 302, n;
const int inf = 23333333;
bool bfs()
{
    vis[S] = ++bfstime, lev[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop();
        //cout << tp << endl;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (edge[i].f == 0 || vis[edge[i].to] == bfstime) continue;
            vis[edge[i].to] = bfstime, lev[edge[i].to] = lev[tp]+1, que.push(edge[i].to);
        }
    }
    //cout << "V" << vis[T] << endl;
    return vis[T] == bfstime;
}

int dfs(int nd, int maxf = inf)
{
    if (nd == T || !maxf) return maxf;
    int ans = 0, t;
    for (int i = head[nd]; i; i = edge[i].next ) {
        if (edge[i].f == 0 || lev[edge[i].to] != lev[nd]+1) continue;
        t = dfs(edge[i].to, min(maxf, edge[i].f));
        ans += t, maxf -= t;
        edge[i].f -= t, edge[edge[i].neg].f += t;
    }
    if (maxf) lev[nd] = -1;
    return ans;
}

int dinic()
{
    int ans = 0;
    while (bfs()) ans += dfs(S);
    return ans;
}

inline int number(int i)
{ return (i-1)* 2+1; }

int stay[MAXN];

int main()
{
    int t; scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        top = 0;
        memset(head, 0, sizeof head);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &stay[i]);
            if (stay[i] == 1) push(number(i)+1, T, 1);
        }
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            int u; scanf("%d", &u);
            if (stay[i] == 0 || (stay[i] == 1 && u == 0))
                push(S, number(i), 1), cnt++;
            push(number(i), number(i)+1, 1);
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++) {
                int u; scanf("%d", &u);
                if (u) push(number(i), number(j)+1, 1);
            }
        //cout << dinic() << endl;
        if (dinic() == cnt) puts("^_^");
        else puts("T_T");
    }
    return 0;
}

SDOI2009 晨跑

Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑、仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑。 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道,Elaxia只能从 一个十字路口跑向另外一个十字路口,街道之间只在十字路口处相交。Elaxia每天从寝室出发 跑到学校,保证寝室编号为1,学校编号为N。 Elaxia的晨跑计划是按周期(包含若干天)进行的,由于他不喜欢走重复的路线,所以 在一个周期内,每天的晨跑路线都不会相交(在十字路口处),寝室和学校不算十字路 口。Elaxia耐力不太好,他希望在一个周期内跑的路程尽量短,但是又希望训练周期包含的天 数尽量长。 除了练空手道,Elaxia其他时间都花在了学习和找MM上面,所有他想请你帮忙为他设计 一套满足他要求的晨跑计划。

不会相交就是点拆边中间流量为1费用为0,最小费用就是边上流量为1费用为长度,然后跑最小费用最大流。
大坑:1->n

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 805, MAXM = 100005;
struct node {
    int to, next, f, c, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k, int l)
{
    ++top, edge[top] = (node){j, head[i], k, l, top+1}, head[i] = top;
    ++top, edge[top] = (node){i, head[j], 0, -l, top-1}, head[j] = top;
}

int inf = 233333333;
int n, m, S = 801, T = 802;
int vis[MAXN], dis[MAXN], pre[MAXN], pre_edge[MAXN];
queue<int> que;

bool spfa()
{
    memset(vis, 0, sizeof vis);
    memset(dis, 127/3, sizeof dis);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop(), vis[tp] = 0;
        //cout << tp << endl;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (!edge[i].f || dis[edge[i].to] <= dis[tp]+edge[i].c) continue;
            dis[edge[i].to] = dis[tp]+edge[i].c;
            pre[edge[i].to] = tp, pre_edge[edge[i].to] = i;
            if (!vis[edge[i].to])
                vis[edge[i].to] = 1, que.push(edge[i].to);
        }
    }
    return dis[T] <= inf;
}

int work(int &cost)
{
    int ans = inf;
    for (int i = T; i != S; i = pre[i]) ans = min(ans, edge[pre_edge[i]].f);
    for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].f -= ans, edge[edge[pre_edge[i]].neg].f += ans;
    cost += dis[T]*ans;
    return ans;
}

int mcf(int &cost)
{
    int ans = 0;
    while (spfa()) ans += work(cost);
    return ans;
}

int main()
{
    scanf("%d%d", &n, &m);
    push(1, n+1, inf, 0); push(n, n+n, inf, 0);
    push(S, 1, inf, 0); push(n+n, T, inf, 0);
    for (int i = 2; i <= n-1; i++) push(i, n+i, 1, 0);
    for (int i = 1; i <= m; i++) {
        int a, b, c; scanf("%d%d%d", &a, &b, &c);
        if (a == 1 && b == n || a == n && b == 1) {
            push(1+n, n, 1, c);
        } else {
            push(a+n, b, inf, c);
        }
    }
    int ans = 0, cost = 0;
    ans = mcf(cost);
    printf("%d %d\n", ans, cost);
    return 0;
}

ZJOI2010 网络扩容

1A…
扩容就是在残量网络上加有费用的无限流量边,为了让他只增加k,在源点和汇点外面接超级源点和超级汇点,流量都为k。然后跑最小费用最大流。

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005, MAXM = 100005;
struct node {
    int to, next, f, c, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k, int l)
{
    ++top, edge[top] = (node){j, head[i], k, l, top+1}, head[i] = top;
    ++top, edge[top] = (node){i, head[j], 0, -l, top-1}, head[j] = top;
}

int inf = 233333333;
int n, m, k, S = 1001, T = 1002;
int vis[MAXN], dis[MAXN], pre[MAXN], pre_edge[MAXN];
queue<int> que;

bool spfa()
{
    memset(vis, 0, sizeof vis);
    memset(dis, 127/3, sizeof dis);
    vis[S] = 1, dis[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop(), vis[tp] = 0;
        //cout << tp << endl;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (!edge[i].f || dis[edge[i].to] <= dis[tp]+edge[i].c) continue;
            dis[edge[i].to] = dis[tp]+edge[i].c;
            pre[edge[i].to] = tp, pre_edge[edge[i].to] = i;
            if (!vis[edge[i].to])
                vis[edge[i].to] = 1, que.push(edge[i].to);
        }
    }
    return dis[T] <= inf;
}

int work(int &cost)
{
    int ans = inf;
    for (int i = T; i != S; i = pre[i]) ans = min(ans, edge[pre_edge[i]].f);
    for (int i = T; i != S; i = pre[i]) edge[pre_edge[i]].f -= ans, edge[edge[pre_edge[i]].neg].f += ans;
    cost += dis[T]*ans;
    return ans;
}

int mcf(int &cost)
{
    int ans = 0;
    while (spfa()) ans += work(cost);
    return ans;
}

struct ep {
    int a, b, c, d;
} epl[MAXM];

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    S = 1, T = n;
    for (int i = 1; i <= m; i++) {
        int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d);
        epl[i] = (ep) {a, b, c, d};
        push(a, b, c, 0);
    }
    int cost = 0, ans;
    ans = mcf(cost);
    printf("%d ", ans);
    T++;
    for (int i = 1; i <= m; i++)
        push(epl[i].a, epl[i].b, inf, epl[i].d);
    push(n, n+1, k, 0);
    cost = 0;
    ans = mcf(cost);
    printf("%d\n", cost);
    return 0;
}

CQOI2009 跳舞

一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会”单向喜欢“)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

把他们拆成只和喜欢的人跳舞的自己和只和不喜欢的人跳舞的自己,然后乱搞。

由于复制的时候出错导致WA*n,以后严禁复制……

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 505, MAXM = 20005;
struct node {
    int to, next, f, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k)
{
    ++top, edge[top] = {j, head[i], k, top+1}, head[i] = top;
    ++top, edge[top] = {i, head[j], 0, top-1}, head[j] = top;
}

int vis[MAXN], bfstime = 0, lev[MAXN];
int inf = 233333333;
int S = 501, T = 502;
queue<int> que;

bool bfs()
{
    vis[S] = ++bfstime, lev[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop();
        //cout << tp << endl;
        for (int i = head[tp]; i; i = edge[i].next) {
            if (vis[edge[i].to] == bfstime || !edge[i].f) continue;
            vis[edge[i].to] = bfstime, lev[edge[i].to] = lev[tp]+1, que.push(edge[i].to);
        }
    }
    return vis[T] == bfstime;
}

int dfs(int nd, int maxf = inf)
{
    if (nd == T || !maxf) return maxf;
    int ans = 0, t;
    for (int i = head[nd]; i; i = edge[i].next) {
        if (!edge[i].f || lev[edge[i].to] != lev[nd] + 1) continue;
        t = dfs(edge[i].to, min(maxf, edge[i].f));
        ans += t, maxf -= t;
        edge[i].f -= t, edge[edge[i].neg].f += t;
    }
    return ans;
}

int dinic()
{
    int ans = 0;
    while (bfs()) ans += dfs(S);
    return ans;
}
int n, k;
char str[55][55];

bool judge(int a)
{
    top = 0; memset(head, 0, sizeof head);
    for (int i = 1; i <= n; i++) {
        push(4*n+i, i, k), push(4*n+i, n+i, inf), push(2*n+i, 5*n+i, k), push(3*n+i, 5*n+i, inf);
        push(S, 4*n+i, a), push(5*n+i, T, a);
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (str[i][j] == 'Y')
                push(n+i, 3*n+j, 1);
            else
                push(i, 2*n+j, 1);
    return dinic() == n*a;
}

int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++)
        scanf("%s", str[i]+1);
    int l = 0, r = 10000000;
    while (l <= r) {
        int mid = (l+r)>>1;
        if (judge(mid)) l = mid+1;
        else r = mid-1;
    }
    printf("%d\n", l-1);
    return 0;
}

CQOI2014 危桥

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿al和a2之间往返an次(从al到a2再从a2到al算一次往返)。同时,Bob希望在岛屿bl和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?

其实还是比较诡异的…
如果正常建图,第一次把a1,b1当源点a2,b2当汇点跑一遍最大流d1,第二次把a1,b2 当源点a2,b1 跑最大流d2。可以证明:可以通行当且仅当d1,d22(an+bn)

定理的充分性是显然的,我们只需要证明必要性(反证)。d1,d22(an+bn),导致“不能通行”的原因只有从a流出的流进入了b,或从b流出的流进入了a。由于两问题对称我们只考虑a进入b。设a1进入b2的流量f1b1进入a2的流量f1,去掉他们后形成的不可增广的网络;a1进入b1的流量f2b2进入a2的流量f2。我可以沿着a1b2a2就可以增广,这与“不可增广的网络”矛盾。

由于要限制次数要将ST连边的流量设为an2bn2

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1005, MAXM = 100005;
struct node {
    int to, next, f, neg;
} edge[MAXM];
int head[MAXN], top = 0;
void push(int i, int j, int k)
{
//    printf("%d--%d-->%d\n", i, k, j);
    ++top, edge[top] = (node){j, head[i], k, top+1}, head[i] = top;
    ++top, edge[top] = (node){i, head[j], 0, top-1}, head[j] = top;  // 反向弧
}

void init()
{
    memset(head, 0, sizeof head);
    top = 0;
}

int vis[MAXN], bfstime = 0, lev[MAXN];
queue<int> que;
int S = 1001, T = 1002;
const int inf = 233333333;

bool bfs()
{
    vis[S] = ++bfstime, lev[S] = 0, que.push(S);
    while (!que.empty()) {
        int tp = que.front(); que.pop();
        for (int i = head[tp]; i; i = edge[i].next) {
            if (!edge[i].f || vis[edge[i].to] == bfstime) continue;
            vis[edge[i].to] = bfstime, lev[edge[i].to] = lev[tp]+1, que.push(edge[i].to);
        }
    }
    return vis[T] == bfstime;
}

int dfs(int nd, int maxf = inf)
{
    if (nd == T || !maxf) return maxf;
    //cout << nd << " " << maxf << endl;
    int ans = 0, t;
    for (int i = head[nd]; i; i = edge[i].next) {
        if (!edge[i].f || lev[edge[i].to] != lev[nd]+1) continue;
        t = dfs(edge[i].to, min(maxf, edge[i].f));
        ans += t, maxf -= t;
        edge[i].f -= t, edge[edge[i].neg].f += t;
    }
    //cout << nd << " " << ans << endl;
    if (maxf) lev[nd] = -1;
    return ans;
}

int dinic()
{
    int ans = 0;
    while (bfs()) ans += dfs(S);
    return ans;
}

int n, a1, a2, an, b1, b2, bn;
char str[55][55];

int main()
{
    while (scanf("%d%d%d%d%d%d%d",&n,&a1,&a2,&an,&b1,&b2,&bn)!=EOF) {
        a1++, a2++, b1++, b2++;
        for (int i = 1; i <= n; i++)
            scanf("%s", str[i]+1);
        init();
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (str[i][j] == 'N') push(i, j, inf);
                else if (str[i][j] == 'O') push(i, j, 2);
        push(S, a1, an<<1), push(a2, T, an<<1);
        push(S, b1, bn<<1), push(b2, T, bn<<1);
        int d1 = dinic();
        init();
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (str[i][j] == 'N') push(i, j, inf);
                else if (str[i][j] == 'O') push(i, j, 2);
        push(S, a1, an<<1), push(a2, T, an<<1);
        push(b1, T, bn<<1), push(S, b2, bn<<1);
        int d2 = dinic();
        //cout << d1 << " " << d2 << endl;
        if (d1 >= 2*(an+bn)&& d2 >= 2*(an+bn)) puts("Yes");
        else puts("No");
    }
    return 0;
}

智障bug集合

SX选手的bug集合

  1. 把两个规模相同的数当成一个数
  2. 复制的时候没有i改成j
  3. head[i]和head[j],反向弧的流量和费用设错。
  4. S和SS搞混
  5. map中没有开long long
  6. 求逆元没有特判0
posted @ 2017-03-02 23:34  ljt12138  阅读(134)  评论(0编辑  收藏  举报