zoukankan      html  css  js  c++  java
  • [网络流24题] 4. 魔术球问题 解题报告

    魔术球问题

    题意

    (n) 个柱子 ((4le n le 55)),

    往这 (n) 个柱子上依次放编号为 $1,2,3,dots $ 的球,

    要求同一个柱子上相邻两球的编号之和为完全平方数,

    求最多能放多少个球.

    思路

    方法一

    考虑二分答案, 每次二分球数,

    设当前有 (t) 个球, 那么这个问题就可以转化为最小路径覆盖问题,

    相当于有 (t) 个点, 点之间有若干条边, 初始状态可以认为是用 (t) 条路径覆盖了这张图, 那么就看哪些路径是可以合并的.

    把每个点拆成两个点, 一个代表出度, 一个代表入度,

    (S) 向代表出度的点连一条容量为 (1) 的边, 代表入度的点向 (T) 连一条容量为 (1) 的边, 点与点之间的边就按照原图连接, 然后跑最大流就行了.


    方法二

    其实不需要二分答案, 只需要逐个把点加入网络中, 然后在残量网络上跑最大流就行了.

    (但是二分还更快一点, 估计是因为逐个加点时, (Dinic) 算法的优势表现不出来, 相当于 "退化" 成了 (EK))

    代码

    方法一

    #include<bits/stdc++.h>
    #define pb push_back
    #define sz size
    using namespace std;
    const int _=6050+7;
    const int __=344850+7;
    const int inf=0x3f3f3f3f;
    int t,n,S,T,d[_],max_flow,result,ans;
    int lst[_],nxt[__],to[__],c[__],tot=1;
    queue<int> q;
    vector<int> plr[55+7];
    void add(int x,int y,int cap){
      nxt[++tot]=lst[x];
      to[tot]=y;
      c[tot]=cap;
      lst[x]=tot;
    }
    void init(){
      tot=1; max_flow=0;
      memset(lst,0,sizeof(lst));
      S=2*n+1; T=2*n+2;
      for(int i=1;i<=n;i++){
        add(S,i,1);
        add(i,S,0);
        add(i+n,T,1);
        add(T,i+n,0);
      }
      for(int i=1;i*i<=2*n;i++)
        for(int j=1;j<=n;j++){
          if(i*i-j<=j) break;
          if(i*i-j>n) continue;
          add(j,i*i-j+n,1);
          add(i*i-j+n,j,0);
        }
    }
    bool bfs(){
      memset(d,0,sizeof(d));
      while(!q.empty()) q.pop();
      d[S]=1; q.push(S);
      while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=lst[u];i;i=nxt[i]){
          int v=to[i];
          if(d[v]||!c[i]) continue;
          d[v]=d[u]+1;
          if(v==T) return 1;
          q.push(v);
        }
      }
      return 0;
    }
    int dfs(int u,int flow){
      if(u==T) return flow;
      int rest=flow;
      for(int i=lst[u];i;i=nxt[i]){
        int v=to[i];
        if(d[v]!=d[u]+1||!c[i]) continue;
        int cost=dfs(v,min(rest,c[i]));
        c[i]-=cost; c[i^1]+=cost;
        rest-=cost;
      }
      return flow-rest;
    }
    void Dinic(){
      int flow;
      while(bfs()){
        do{
          flow=dfs(S,inf);
          max_flow+=flow;
        }while(flow);
      }
      result=n-max_flow;
    }
    void save(){
      int cnt=0;
      for(int i=lst[T];i;i=nxt[i]){
        if(c[i]) continue;
        int u=to[i]-n;
        cnt++;
        vector<int>().swap(plr[cnt]);
        while(1){
          int las=u;
          plr[cnt].pb(u);
          for(int i=lst[u];i;i=nxt[i])
    	if(to[i]-n<=n&&!c[i]){ u=to[i]-n; break; }
          if(u==las) break;
        }
      }
    }
    bool judge(int mid){
      n=mid;
      init();
      Dinic();
      if(result<=t){
        if(result==t) save();
        return 1;
      }
      else return 0;
    }
    void print(){
      printf("%d
    ",ans);
      for(int i=1;i<=t;i++){
        for(int j=0;j<(int)plr[i].sz();j++)
          printf("%d ",plr[i][j]);
        putchar('
    ');
      }
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      cin>>t;
      int l=11,r=3025;
      while(l<=r){
        int mid=(l+r)>>1;
        if(judge(mid)){ ans=mid; l=mid+1; }
        else r=mid-1;
      }
      print();
      return 0;
    }
    

    方法二

    #include<bits/stdc++.h>
    #define pb push_back
    #define sz size
    using namespace std;
    const int _=6050+7;
    const int __=344850+7;
    const int inf=0x3f3f3f3f;
    int t,n,m=3025,S=6051,T=6052,d[_],max_flow,ans;
    int lst[_],nxt[__],to[__],c[__],tot=1;
    queue<int> q;
    vector<int> plr[55+7];
    void add(int x,int y,int cap){
      nxt[++tot]=lst[x];
      to[tot]=y;
      c[tot]=cap;
      lst[x]=tot;
    }
    void init(){
      n++;
      add(S,n,1); add(n,S,0);
      add(n+m,T,1); add(T,n+m,0);
      for(int i=1;i*i-n<n;i++){
        int j=i*i-n;
        if(j<0) continue;
        if(j<n){
          add(j,n+m,1);
          add(n+m,j,0);
        }
        else if(j>n){
          add(n,j+m,1);
          add(j+m,n,0);
        }
      }
    }
    bool bfs(){
      memset(d,0,sizeof(d));
      d[S]=1; q.push(S);
      while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=lst[u];i;i=nxt[i]){
          int v=to[i];
          if(d[v]||!c[i]) continue;
          d[v]=d[u]+1;
          if(v==T) return 1;
          q.push(v);
        }
      }
      return 0;
    }
    int dfs(int u,int flow){
      if(u==T) return flow;
      int rest=flow;
      for(int i=lst[u];i;i=nxt[i]){
        int v=to[i];
        if(d[v]!=d[u]+1||!c[i]) continue;
        int cost=dfs(v,min(rest,c[i]));
        c[i]-=cost; c[i^1]+=cost;
        rest-=cost;
      }
      return flow-rest;
    }
    void Dinic(){
      int flow;
      while(bfs())
        do{
          flow=dfs(S,inf);
          max_flow+=flow;
        }while(flow);
    }
    void save(){
      int cnt=0;
      for(int k=lst[T];k;k=nxt[k]){
        if(c[k]) continue;
        int u=to[k]-m; cnt++;
        vector<int>().swap(plr[cnt]);
        while(1){
          int las=u;
          plr[cnt].pb(u);
          for(int i=lst[u];i;i=nxt[i])
    	if(to[i]!=S&&!c[i]){ u=to[i]-m; break; }
          if(u==las) break;
        }
      }
    }
    bool idk(){
      init();
      Dinic();
      if(n-max_flow==t) save();
      return n-max_flow<=t;
    }
    void print(){
      n--;
      printf("%d
    ",n);
      for(int i=1;i<=t;i++){
        for(int j=0;j<(int)plr[i].sz();j++)
          printf("%d ",plr[i][j]);
        putchar('
    ');
      }
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      cin>>t;
      while(idk());
      print();
      return 0;
    }
    
  • 相关阅读:
    转: android emulator 命令详解
    ubuntu 环境变量PATH的修改
    ubuntu创建、删除文件及文件夹,强制清空回收站方法
    51单片机的P0口工作原理详细讲解
    smartconfig配置模式
    (网卡)混杂模式
    Scrapy shell使用
    Splash 笔记
    Lua一般都用来干什么,有什么优点
    python dict转json并保存文件
  • 原文地址:https://www.cnblogs.com/BruceW/p/12185537.html
Copyright © 2011-2022 走看看