zoukankan      html  css  js  c++  java
  • P2765 魔术球问题

    洛谷

    假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为1,2,3,...的球。

    (1)每次只能在某根柱子的最上面放球。

    (2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。

    试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可放11 个球。

    题解:

    • 先将其转化为一张图  并把能连的边都连上   数字小的连数字大的,因为从小到大放入
    • 可以将其转化为最小路径覆盖  每条路径就是每个石柱上的一串数字
    • 显然当最少路径大于石柱个数的时候  不能再放了
    • 不断更新二分图即可
    • 注意每次跑的是残量网络 所以累和即可
    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    const int N=1e5+10;
    const int M=1e5+10;
    struct Edge {
        int to, next, w;
    } edge[M<<1];
    int head[N],cur[N],pos=1,level[N];
    void add(int a, int b, int c) {
        edge[++pos] = (Edge){b, head[a], c};head[a] = pos;
        edge[++pos] = (Edge){a, head[b], 0};head[b] = pos;
    }
    bool bfs(int s, int t) {
        memset(level, 0, sizeof level);
        queue<int> q;
        level[s] = 1;
        q.push(s);
        while (!q.empty()) {
            int pos = q.front();q.pop();
            for (int i = head[pos]; i; i = edge[i].next) {
                int v = edge[i].to;
                if (!edge[i].w || level[v]) continue;
                level[v] = level[pos] + 1;
                q.push(v);
            }
        }
        return level[t];
    }
    int dfs(int s, int t, int flow) {
        if(s==t||flow==0)return flow;
        int f,ret = 0;
        for (int &i = cur[s],v; i; i = edge[i].next) {
             v = edge[i].to;
            if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,edge[i].w)))>0) {
                edge[i].w -= f;
                edge[i ^ 1].w += f;
                flow -= f;
                ret += f;
                if(!flow)break;
            }
        }
        return ret;
    }
    int dinic(int s, int t) {
        int ret = 0;
        while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, inf);
        return ret;
    }
    int spr[N],s,t,n,vis2[N],to[N];
    int main() {
        cin>>n;s=0,t=N-1;int T=10000;
    
        for(int i=1;i<=10000;i++)spr[i]=i*i;
        int pos=1,sum=0;
        while(1) {
            add(s,pos,1);add(pos+T,t,1);
            int x=lower_bound(spr+1,spr+1+1000,pos)-spr;
            for(int j=2*x;j>=1;j--) {
                int temp=spr[j]-pos;
                if(temp>0&&temp<pos)add(temp,pos+T,1);
            }
            sum+=dinic(s,t);
            if(pos-sum>n)break;
            pos++;
        }
        pos--;
        cout<<pos<<endl;
        for(int i=1;i<=pos;i++)
            for(int j=head[i];j;j=edge[j].next) if(!edge[j].w&&edge[j].to!=s) {
                to[i]=edge[j].to-T;break;
            }
        for(int i=1;i<=pos;i++) {
            if(vis2[i])continue;
            for(int k=i;k;k=to[k])
                vis2[k]=1,printf("%d ",k);
            printf("
    ");
        }
    }
    View Code
  • 相关阅读:
    命令拷屏之网络工具
    PHP 设计模式 笔记与总结(1)命名空间 与 类的自动载入
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 计蒜客 1251 仙岛求药
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 蓝桥杯 算法训练 字符串合并
    Java实现 LeetCode 143 重排链表
    Java实现 LeetCode 143 重排链表
  • 原文地址:https://www.cnblogs.com/bxd123/p/11808587.html
Copyright © 2011-2022 走看看