魔术球问题【网络流24题】【最大流Dinic+隐式图推理+拆点建边】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/88693962

题目链接


  这道题目当真是很好,我推了两天然后有了个这样的思路(期间BUG找了半天左右、思路大致也是想了半天)…… 呜呜呜,好难呐的说呢。

  这里因为点只有50个,所以我用了一种新的思路来接近最大值(其实最后推完之后会发现,到N=50的时候,也就1300不到的),虽然我数组开的很大(因为我一开始是不确定大小的,保险起见,甚至还无限的逼近了时间复杂度),这道题的主心骨就是:

最小边覆盖 = 目前的点的总数 - 最大匹配

  为什么这样说呢,因为给了N个台子,也就是在要求着最后的台子的个数不能超过N,那么就是说我们最多也就是N条边,所以这就是判断的条件了,我们每次都不断的往里面插入点,最后要求的是点的总数 - 最大流的数目 ≤ 最多允许的边的数目(N)

  那么不如一个一个的加点进去,知道不满足的时候,我们退出循环,然后就能得到答案了,接下来的建边就是拆点建边的思想,可以自己推一下,也可以看我的Code,其实不是特别难,跟之前做的那道建边的方式是一样的诶…… 


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 5e4 + 5;
const int maxE = 2e6 + 7;
const int S = 0, T = 3e4 + 1;
int N, sqr[maxN], head[maxN], cur[maxN], cnt, top[maxN], tot;
bool read[maxN];
struct Eddge
{
    int nex, to, val;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
}edge[maxE], path[maxE];
inline void addEddge(int u, int v, int val)
{
    edge[cnt] = Eddge(head[u], v, val);
    head[u] = cnt++;
}
inline void addPath(int u, int v)
{
    path[tot] = Eddge(top[u], v);
    top[u] = tot++;
}
int deep[maxN];
queue<int> Q;
bool bfs()
{
    while(!Q.empty()) Q.pop();
    Q.push(S);  memset(deep, 0, sizeof(deep));  deep[S] = 1;
    while(!Q.empty())
    {
        int u = Q.front();  Q.pop();
        for(int i=head[u], v, flow; ~i; i=edge[i].nex)
        {
            v = edge[i].to; flow = edge[i].val;
            if(!deep[v] && flow)
            {
                deep[v] = deep[u] + 1;
                Q.push(v);
            }
        }
    }
    return deep[T];
}
int dfs(int u, int flow)
{
    if(u == T) return flow;
    for(int &i = cur[u], v, dist; ~i; i=edge[i].nex)
    {
        v = edge[i].to; dist = edge[i].val;
        if(deep[v] == deep[u] + 1 && dist)
        {
            int di = dfs(v, min(flow, dist));
            if(di)
            {
                edge[i].val -= di;
                edge[i^1].val += di;
                return di;
            }
        }
    }
    return 0;
}
int Dinic()
{
    int ans = 0, tmp = 0;
    while(bfs())
    {
        for(int i=S; i<=T; i++) cur[i] = head[i];
        while((tmp = dfs(S, INF))) ans += tmp;
    }
    return ans;
}
void OUT_put(int u)
{
    read[u] = true;
    printf("%d ", u);
    for(int i=top[u], v; ~i; i=path[i].nex)
    {
        v = path[i].to;
        if(read[v]) continue;
        OUT_put(v);
    }
}
inline void init()
{
    cnt = tot = 0;
    memset(head, -1, sizeof(head)); memset(read, false, sizeof(read));  memset(top, -1, sizeof(top));
}
int main()
{
    scanf("%d", &N);
    for(int i=1; i<maxN; i++) sqr[i] = i * i;
    init();
    int ans = 0, point = 0, team = 0;
    while(true)
    {
        addEddge(S, ++point, 1);
        addEddge(point, S, 0);
        addEddge(point + 5000, T, 1);
        addEddge(T, point + 5000, 0);
        int kk = (int)(lower_bound(sqr + 1, sqr + 1000, point) - sqr);
        for(int i = kk<<1; i>=1; i--)
        {
            int tmp = sqr[i] - point;
            if(tmp <= 0 || tmp >= point) continue;
            addEddge(tmp, point + 5000, 1);
            addEddge(point + 5000, tmp, 0);
        }
        team += Dinic();
        if(point - team > N) break;
        ans = point;
    }
    printf("%d\n", ans);
    for(int u=1; u<=ans; u++)
    {
        for(int i=head[u], v, val; ~i; i=edge[i].nex)
        {
            v = edge[i].to; val = edge[i].val;
            if(v > 5000 && v < T && !val) addPath(u, v - 5000);
        }
    }
    for(int i=1; i<=ans; i++)
    {
        if(read[i]) continue;
        OUT_put(i);
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/88693962