2019 Petrozavodsk Winter Camp, Yandex Cup C. Diverse Singing 上下界网络流

建图一共建四层 第一层为N个歌手 第二层为{pi,li} 第三层为{si,li} 第四层为M首歌

除了S和第一层与第三层与T之间的边为[1,INF] 其他边均为[0,1]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef int JQK;
const JQK INF = 1000000005;
struct node {
        int p, s, l;
        bool operator <(const node &rhs) const {
                if (p != rhs.p)
                        return p > rhs.p;
                else {
                        if (s != rhs.s)
                                return s > rhs.s;
                        else
                                return l > rhs.l;
                }
        }
} nodecnt;
int n, m, k, s1, t1, s2, t2;
map<pair<int, int>, int> pl, sl;
map<int, pair<int, int> > plb, slb;
map<node, int> psl;
vector<int> anser;
namespace dinic {
        const int MAXN = 30050;
        const int MAXM = 100050;
        const JQK INF = 1000000050;
        int Head[MAXN], cur[MAXN], lev[MAXN], to[MAXM << 1], nxt[MAXM << 1], ed = 1;
        int S, T, SS, TT, MAXP;
        JQK f[MAXM << 1], totflow[MAXN];
        inline void addedge(int u, int v, JQK cap) {
                to[++ed] = v;
                nxt[ed] = Head[u];
                Head[u] = ed;
                f[ed] = cap;
                to[++ed] = u;
                nxt[ed] = Head[v];
                Head[v] = ed;
                f[ed] = 0;
                return;
        }
        inline void add(int u, int v, JQK caplow, JQK captop) {
                addedge(u, v, captop - caplow);
                totflow[u] -= caplow, totflow[v] += caplow;
                return ;
        }
        inline bool BFS() {
                int u;
                for (int i = 0; i <= MAXP + 1; i++) {
                        lev[i] = -1;
                }
                //memset(lev, -1, sizeof(lev));
                queue<int>q;
                lev[S] = 0;
                q.push(S);
                while (q.size()) {
                        u = q.front();
                        q.pop();
                        for (int i = Head[u]; i; i = nxt[i])
                                if (f[i] && lev[to[i]] == -1) {
                                        lev[to[i]] = lev[u] + 1;
                                        q.push(to[i]);
                                        /*
                                        if (to[i] == T)
                                        {
                                                return 1;
                                        }
                                        magic one way optimize
                                        */
                                }
                }
                for (int i = 0; i <= MAXP + 1; i++) {
                        cur[i] = Head[i];
                }
                //memcpy(cur, Head, sizeof Head);
                return lev[T] != -1;
        }
        inline JQK DFS(int u, JQK maxf) {
                if (u == T || !maxf) {
                        return maxf;
                }
                JQK cnt = 0, tem;
                for (int &i = cur[u]; i; i = nxt[i])
                        if (f[i] && lev[to[i]] == lev[u] + 1) {
                                tem = DFS(to[i], min(maxf, f[i]));
                                maxf -= tem;
                                f[i] -= tem;
                                f[i ^ 1] += tem;
                                cnt += tem;
                                if (!maxf) {
                                        break;
                                }
                        }
                if (!cnt) {
                        lev[u] = -1;
                }
                return cnt;
        }
        JQK Dinic() {
                JQK ans = 0;
                while (BFS()) {
                        ans += DFS(S, INF);
                }
                return ans;
        }
        void del(int x) {
                for (int i = Head[x]; i; i = nxt[i])
                        f[i] = f[i ^ 1] = 0;
        }
        void init(int S1, int T1, int S2, int T2) {
                for (int i = 0; i <= MAXP + 1; i++) {
                        totflow[i] = Head[i] = 0;
                }
                ed = 1;
                S = S1;
                T = T1;
                SS = S2;
                TT = T2;
                return;
        }
        inline JQK pushdownflow(int x) {
                JQK sum = 0;
                for (int i = 1; i <= x; i++) {
                        if (totflow[i] > 0) {
                                addedge(SS, i, totflow[i]);
                                sum += totflow[i];
                        } else if (totflow[i] < 0) {
                                addedge(i, TT, -totflow[i]);
                        }
                }
                return sum;//sum==dinic 循环流有解
        }
        JQK work() { //有源汇最大流
                JQK ans = 0;
                JQK sum = pushdownflow(TT - 2);
                addedge(T, S, INF);
                swap(S, SS), swap(T, TT);
                if (sum != Dinic()) { //Dinic(SS,TT) 求出一个有源汇有上下界可行流.此时的流不一定最大.
                        cout << -1 << endl;
                        return 0;
                }
                ans = f[ed]; //可行流流量
                f[ed] = f[ed ^ 1] = 0;
                swap(S, SS), swap(T, TT); //Dinic(S,T)
                ans += Dinic();//新增广出的s-t流量
                cout << ans << endl;
                for (int i = n + m + 1; i <= n + m + k; i++) {
                        for (int j = Head[i]; j; j = nxt[j]) {
                                int v = to[j];
                                if (v >= n + m + k + 1 && v <= n + m + 2 * k && f[j] == 0) {
                                        nodecnt.p = plb[i].first;
                                        nodecnt.s = slb[v].first;
                                        nodecnt.l = slb[v].second;
                                        anser.push_back(psl[nodecnt]);
                                }
                        }
                }
                sort(anser.begin(), anser.end());
                for (int v : anser) {
                        cout << v << " ";
                }
                return ans;
        }
}
int main() {
        int u, v;
        JQK c;
        scanf("%d %d %d", &n, &m, &k);
        dinic::MAXP = n + m + 2 * k + 5;
        s1 = n + m + 2 * k + 1;
        t1 = s1 + 1;
        s2 = t1 + 1;
        t2 = s2 + 1;
        dinic::init(s1, t1, s2, t2); //S T SS TT
        for (int i = 1; i <= n; i++)
                dinic::add(s1, i, 1, INF);
        for (int i = n + 1; i <= n + m; i++)
                dinic::add(i, t1, 1, INF);
        for (int i = 1; i <= k; i++) {
                scanf("%d %d %d", &u, &v, &c);
                nodecnt.p = u, nodecnt.s = v, nodecnt.l = c;
                if (!psl[nodecnt])
                        psl[nodecnt] = i;
                if (!pl[make_pair(u, c)]) {
                        pl[make_pair(u, c)] = n + m + i;
                        plb[n + m + i] = make_pair(u, c);
                        dinic::add(u, n + m + i, 0, 1);
                }
                if (!sl[make_pair(v, c)]) {
                        sl[make_pair(v, c)] = n + m + k + i;
                        slb[n + m + k + i] = make_pair(v, c);
                        dinic::add(n + m + k + i, n + v, 0, 1);
                }
                dinic::add(pl[make_pair(u, c)], sl[make_pair(v, c)], 0, 1);
        }
        dinic::work();
        return 0;
}

 

转载于:https://www.cnblogs.com/Aragaki/p/11590378.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值