网络流24题(四)
网络流24题(4)
四、魔术球问题
题目描述
假设有 \(n\) 根柱子,现要按下述规则在这 \(n\) 根柱子中依次放入编号为 \(1\),\(2\),\(3\),...的球“
- 
每次只能在某根柱子的最上面放球。 
- 
同一根柱子中,任何 \(2\) 个相邻球的编号之和为完全平方数。 
试设计一个算法,计算出在 \(n\) 根柱子上最多能放多少个球。例如,在 \(4\) 根柱子上最多可放 \(11\) 个球。
对于给定的 \(n\),计算在 \(n\) 根柱子上最多能放多少个球。
输入格式
只有一行一个整数 \(n\),代表柱子数。
输出格式
本题存在 Special Judge。
请将 \(n\) 根柱子上最多能放的球数以及相应的放置方案输出。
输出的第一行是球数。
接下来的 \(n\) 行,每行若干个整数,代表一根柱子上的球的编号,数字间用单个空格隔开。
题解
模型:
如果有\(k\)个球,那么建图,转换为\(DAG\)最小覆盖。
建图与实现:
我们可以这么建一张图:
对每一对\((i,j)\),如果\(i+j\)是一个平方数,那么我们就让\(i\)与\(j\)之间连一条有向边,方向为小的指向大的,不难发现这是一张\(DAG\)图。
手玩之后发现,对于\(n\)个柱子的球的个数\(k\)公式为\(k =floor(\frac{n^2}{2})-1\)。
(关于这个结论可以看这个证明,并且在这里面有一种贪心写法)
于是参照之前的写法写即可。
我的网络流方案于网上的不太相同,我的写法大概快了十倍。
网上的写法大概是不断的增加球,并对其不断地求最小路径覆盖,对于每一个路径覆盖的值都找最多的球数。更详细的方法可以找其他的资料查看。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll N = 3500,M = 2e5+5,inf = 0x3f3f3f3f;
ll head[N],cnt = 1;
struct Edge{ll to,w,nxt;}edge[M];
void add(ll u,ll v,ll w){
    edge[++cnt].to = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}
ll n,m,s,t,lv[N],cur[N];
bool bfs(){
    memset(lv, -1, sizeof(lv));
    lv[s] = 0;
    memcpy(cur, head, sizeof(head));
    queue<ll> q;q.push(s);
    while (!q.empty()){
        int p = q.front();q.pop();
        for (ll eg = head[p]; eg; eg = edge[eg].nxt){
            ll to = edge[eg].to, vol = edge[eg].w;
            if (vol > 0 && lv[to] == -1)lv[to] = lv[p] + 1, q.push(to);
        }
    }
    return lv[t] != -1;
}
ll dfs(ll p = s, ll flow = inf){
    if (p == t)return flow;
    int rmn = flow;
    for (ll &eg = cur[p]; eg; eg = edge[eg].nxt){
        if (!rmn)break;
        int to = edge[eg].to, vol = edge[eg].w;
        if (vol > 0 && lv[to] == lv[p] + 1){
            ll c = dfs(to, min(vol, rmn));
            rmn -= c;
            edge[eg].w -= c;
            edge[eg ^ 1].w += c;
        }
    }
    return flow - rmn;
}
ll dinic(){
    ll ans = 0;
    while(bfs()) ans += dfs();
    return ans;
}
ll f[N],vis[N];
void print(){
    memset(f,-1,sizeof f);
    for(ll eg = head[0];eg;eg = edge[eg].nxt){
        if(edge[eg].w == 0){
            ll v = edge[eg].to;
            for(ll j = head[v];j;j = edge[j].nxt){
                if(edge[j].w == 0){
                    f[v] = edge[j].to-n;
                    vis[edge[j].to-n] = true;
                }
            }
        }
    }
    for(ll i = 1;i <= n;i++){
        if(!vis[i]){
            ll x = i;
            cout<<x;
            while(f[x]!=-1){
                cout<<' '<<f[x];
                x = f[x];
            }
            cout<<endl;
        }
    }
}
bool check(ll x){
    ll y = sqrt(x);
    return x == y*y;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;n++;
    ll k = floor(n*n/2)-1;
    n = k;
    cout<<n<<endl;
    for(ll i = 1;i <= n;i++) {
        add(0,i,1);add(i,0,0);
        add(i+n,2*n+1,1);add(2*n+1,i+n,0);
    }
    for(ll i = 1;i <= n;i++){
        for(ll j = i+1;j <= n;j++){
            if(check(i+j)){
                add(i,j+n,1);
                add(j+n,i,0);
            }
        }
    }
    s = 0,t = 2*n+1;
    ll ss = dinic();
    print();
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号