• [网络流24题] 魔术球问题 (最大流)


    洛谷传送门 LOJ传送门

    脑抽写了个费用流$T$飞了,看了题解才明白是怎么跑最大流的

    这道题有一个贪心,如果小于它的数没有能和它之和是完全平方数的,那么它一定要新建一个柱子

    证明可以看poorpool神犇的这篇博客

    由于每个点只能用一次,所以每个点$x$拆成$2$个点$x1$和$x2$,$x1$和源点相连,$x2$和汇点相连,流量均为$1$

    而如果两个数$x,y$能构成完全平方数,那么$x1$连接$y2$

    我们从小到大遍历每个数$x$,然后在图内加入$x2$,如果产生了一条新流,说明$x$能找到一个$y(y<x)$,$x+y$是完全平方数

    否则,我们新加入一个柱子

    然后不论能否产生新流,把$x1$加入到图中

    验证是否产生新流可以用$Dinic$最大流实现

    为什么要这么做呢?

    我们是动态往图里加的点,每次加完点以后,如果情况合法,会产生一条新流。

    如果不这么做,我们每次要重新建边,大大拉高的时间复杂度

    如何记录方案呢?

    一个柱子里的点会形成一条链(即使在网络流图内它看起来不是一条链)。

    可以向并查集一样,开一个数组,在$Dinic$里记录每个点的流量流向哪个位置就行了

      1 #include <cmath>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 8010
      6 #define M1 40010
      7 #define ll long long
      8 #define dd double
      9 #define inf 0x3f3f3f3f
     10 using namespace std;
     11 
     12 int gint()
     13 {
     14     int ret=0,fh=1;char c=getchar();
     15     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     16     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     17     return ret*fh;
     18 }
     19 struct Edge{
     20 int head[N1],to[M1<<1],nxt[M1<<1],flow[M1<<1],cte;
     21 void ae(int u,int v,int F)
     22 {
     23     cte++; to[cte]=v; flow[cte]=F; 
     24     nxt[cte]=head[u]; head[u]=cte;
     25 }
     26 }e,E;
     27 int n,m,K,S,T,F,mx;
     28 int que[M1],hd,tl,dep[N1],cur[N1],pre[N1];
     29 int bfs()
     30 {
     31     int x,j,v;
     32     memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur));
     33     hd=1,tl=0; que[++tl]=S; dep[S]=0; 
     34     while(hd<=tl)
     35     {
     36         x=que[hd++];
     37         for(j=e.head[x];j;j=e.nxt[j])
     38         {
     39             v=e.to[j];
     40             if( e.flow[j]>0 && dep[v]==-1 )
     41                 dep[v]=dep[x]+1, que[++tl]=v;
     42         }
     43     }
     44     return dep[T]!=-1;
     45 }
     46 int dfs(int x,int limit)
     47 {
     48     int j,v,flow,ans=0; if(x==T||!limit) return limit;
     49     for(j=cur[x];j;j=e.nxt[j])
     50     {
     51         cur[x]=j; v=e.to[j];
     52         if( dep[v]==dep[x]+1 && (flow=dfs(v,min(e.flow[j],limit))) )
     53         {
     54             limit-=flow; ans+=flow;
     55             e.flow[j]-=flow; e.flow[j^1]+=flow;
     56             if(v>n*n&&v<=2*n*n) pre[x]=v-n*n;
     57             if(!limit) break;
     58         }
     59     }
     60     return ans;
     61 }
     62 
     63 int stk[N1],tp;
     64 
     65 int de;
     66 int Dinic()
     67 {
     68     int mxflow=0;
     69     while(bfs())
     70         mxflow+=dfs(S,inf);
     71     return mxflow;
     72 }
     73 void solve()
     74 {
     75     int i,j,k,sq,num=0,ans,x;
     76     S=0; T=2*mx+1; e.cte=1;
     77     for(i=1;i<=mx;i++)
     78     {
     79         //e.ae(i,i+mx,1); e.ae(i+mx,i,0);
     80         for(j=n;j>1;j--)
     81         {
     82             k=j*j-i;
     83             if(k>0&&k<i) 
     84                 e.ae(k,i+mx,1),e.ae(i+mx,k,0);
     85         }
     86         e.ae(i+mx,T,1); e.ae(T,i+mx,0); 
     87         if(Dinic()<=0){
     88             if(num+1>n){ ans=i-1; break;}
     89             stk[++tp]=i; num++;
     90         }
     91         e.ae(S,i,1); e.ae(i,S,0); 
     92     }
     93     printf("%d
    ",ans);
     94     for(i=1;i<=n;i++)
     95     {
     96         x=stk[i]; 
     97         while(x) printf("%d ",x), x=pre[x];
     98         puts("");
     99     }
    100 }
    101 
    102 int main()
    103 {
    104     scanf("%d",&n); mx=n*n;
    105     solve();
    106     return 0;
    107 }
  • 相关阅读:
    你会做夹具吗?(一)
    DDR3布线设计要点总结
    PCB设计要点-DDR3布局布线技巧及注意事项
    走进JEDEC,解读DDR(下)
    [转]关于STM32 PB3 PB4 如何设置成普通GPIO的配置
    [转]Verilog有符号数与无符号数作运算
    [转]实用光电二极管pd的采样电路
    STM32外部8M晶振不启动
    ALTCLKCTRL核的作用
    [转]如何在Altium Designer中将PCB生成PDF?
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10297663.html
Copyright © 2020-2023  润新知