• bzoj 5120 [2017国家集训队测试]无限之环——网络流


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5120

    旋转的话相当于去掉一个插头、新增一个插头,所以在这两个插头之间连边并带上费用即可。

    网格图可以黑白染色,转化为相邻格子间插头的匹配问题。

    注意:

    1.黑白染色不是移动一格就 fx = ! fx ;每换一行,开头位置的颜色应该和上一行的开头不一样!不然有偶数列的话自己原来写的那个染色就崩了;

    2. L 形的判断不是 d&(d>>1) 判断是否有两个相邻的1,如果是第一个位置和最后一个位置是1的话(9)就判断不出来了!可以判断 d != 5 && d != 10 ;

    3.对于无解的判断,比较好的是判断插头个数的是不是流量的两倍。

    然后就能很慢地 A 了。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=8005,K=2005,M=K<<4,INF=N;//<<4:*6 for trans *2 for between
    int n,m,t,bh[K][K],hd[N],xnt=1,to[M],nxt[M],cap[M],w[M],bin[5];//=1!
    int dis[N],pre[N],info[N],ans,val,flow; bool ins[N];
    queue<int> q;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mn(int a,int b){return a<b?a:b;}
    void upd(int &x){x>=4?x-=4:0;}
    void add(int x,int y,int z)
    {
      if(!x||y==t)val++;//
      to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=1;w[xnt]=z;
      to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;w[xnt]=-z;
    }
    void init()
    {
      int bin[5];
      bin[0]=1;for(int i=1;i<4;i++)bin[i]=bin[i-1]<<1;
      bool Fx=0,fx=0;
      for(int i=1;i<=n;i++,Fx=!Fx)/////Fx!!!!!
        for(int j=1,fx=Fx;j<=m;j++,fx=!fx)
          {
        int d=rdn(),ct=0;
    
        if(!fx){for(int k=0;k<4;k++)if(d&bin[k])ct++,add(0,k+bh[i][j],0);}
        else {for(int k=0;k<4;k++)if(d&bin[k])ct++,add(k+bh[i][j],t,0);}
        if(ct==1||ct==3)///ct==1:not a chain but 1,1,2
          {
            int x;//caution for ct=1|3 the diff
            if(ct==1) {for(int k=0;k<4;k++)if(d&bin[k]){x=k;break;}}
            else {for(int k=0;k<4;k++)if(!(d&bin[k])){x=k;break;}}
            int y=x^2,cr=x+bh[i][j];
            for(int k=0;k<4;k++)
              if(k!=x)(fx^(ct==3))?add(k+bh[i][j],cr,1+(k==y)):add(cr,k+bh[i][j],1+(k==y));
          }
        //    else if(ct==2&&(d&(d>>1)))//L
        else if(ct==2&&(d!=5&&d!=10))/////caution 9!!!
          {
            for(int k=0;k<4;k++)
              if(d&bin[k])fx?add((k^2)+bh[i][j],k+bh[i][j],1):add(k+bh[i][j],(k^2)+bh[i][j],1);
          }
        if(!fx)
          {
            if(i>1)add(bh[i][j],2+bh[i-1][j],0);
            if(j<m)add(1+bh[i][j],3+bh[i][j+1],0);
            if(i<n)add(2+bh[i][j],bh[i+1][j],0);
            if(j>1)add(3+bh[i][j],1+bh[i][j-1],0);
          }
          }
    }
    bool spfa()
    {
      memset(dis,0x3f,sizeof dis);dis[0]=0;
      info[0]=INF;info[t]=0; q.push(0);ins[0]=1;
      while(q.size())
        {
          int k=q.front();q.pop();ins[k]=0;
          for(int i=hd[k],v;i;i=nxt[i])
        if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
          {
            dis[v]=dis[k]+w[i];
            pre[v]=i;info[v]=Mn(info[k],cap[i]);
            if(!ins[v])q.push(v),ins[v]=1;
          }
        }
      return info[t];
    }
    void ek()
    {
      int s=info[t]; flow+=s; ans+=dis[t]*s;//dis[t]!
      for(int i=pre[t];i;i=pre[to[i^1]])
        {cap[i]-=s;cap[i^1]+=s;}
    }
    int main()
    {
      n=rdn();m=rdn();t=1;
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++,t+=4)bh[i][j]=t;
      init();  if(val&1){puts("-1");return 0;}//
      while(spfa())ek();  printf("%d
    ",flow<<1==val?ans:-1);///
      return 0;
    }
    View Code

     还学习了多路增广SPFA算法。大概适用于边权变化范围很小的那种吧。

    因为边权相近,所以期望做一次SPFA之后能不仅更新出一条路,还能更多地更新,因为算出来的 dis[ ] 可能对很多条路都适用。

    所以就在SPFA之后按照 dis[ ] 来 dfs ,找找所有合法的路径。在这道题上真的能快好多。

    注意 dfs 要打 vis 标记,走过的就不再走了。因为网络里可能有环,这个又是按 dis 来走的,所以比如有很多0权边的话,就可能死循环。dinic 没有这个问题是因为它是按 dfn 来走的,dfn 弄出来的一定是 DAG 。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=8005,K=2005,M=K<<4,INF=N;//<<4:*6 for trans *2 for between
    int n,m,t,bh[K][K],hd[N],xnt=1,cur[N],to[M],nxt[M],cap[M],w[M],bin[5];//=1!
    int dis[N],pre[N],info[N],ans,val,flow; bool ins[N];
    queue<int> q;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int Mn(int a,int b){return a<b?a:b;}
    void upd(int &x){x>=4?x-=4:0;}
    void add(int x,int y,int z)
    {
      if(!x||y==t)val++;//
      to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=1;w[xnt]=z;
      to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;w[xnt]=-z;
    }
    void init()
    {
      int bin[5];
      bin[0]=1;for(int i=1;i<4;i++)bin[i]=bin[i-1]<<1;
      bool Fx=0,fx=0;
      for(int i=1;i<=n;i++,Fx=!Fx)/////Fx!!!!!
        for(int j=1,fx=Fx;j<=m;j++,fx=!fx)
          {
        int d=rdn(),ct=0;
    
        if(!fx){for(int k=0;k<4;k++)if(d&bin[k])ct++,add(0,k+bh[i][j],0);}
        else {for(int k=0;k<4;k++)if(d&bin[k])ct++,add(k+bh[i][j],t,0);}
        if(ct==1||ct==3)///ct==1:not a chain but 1,1,2
          {
            int x;//caution for ct=1|3 the diff
            if(ct==1) {for(int k=0;k<4;k++)if(d&bin[k]){x=k;break;}}
            else {for(int k=0;k<4;k++)if(!(d&bin[k])){x=k;break;}}
            int y=x^2,cr=x+bh[i][j];
            for(int k=0;k<4;k++)
              if(k!=x)(fx^(ct==3))?add(k+bh[i][j],cr,1+(k==y)):add(cr,k+bh[i][j],1+(k==y));
          }
        //    else if(ct==2&&(d&(d>>1)))//L
        else if(ct==2&&(d!=5&&d!=10))/////caution 9!!!
          {
            for(int k=0;k<4;k++)
              if(d&bin[k])fx?add((k^2)+bh[i][j],k+bh[i][j],1):add(k+bh[i][j],(k^2)+bh[i][j],1);
          }
        if(!fx)
          {
            if(i>1)add(bh[i][j],2+bh[i-1][j],0);
            if(j<m)add(1+bh[i][j],3+bh[i][j+1],0);
            if(i<n)add(2+bh[i][j],bh[i+1][j],0);
            if(j>1)add(3+bh[i][j],1+bh[i][j-1],0);
          }
          }
    }
    bool spfa()
    {
      memset(ins,0,sizeof ins);
      memset(dis,0x3f,sizeof dis);dis[0]=0;
      info[0]=INF;info[t]=0; q.push(0);ins[0]=1;
      while(q.size())
        {
          int k=q.front();q.pop();ins[k]=0;
          for(int i=hd[k],v;i;i=nxt[i])
        if(cap[i]&&dis[v=to[i]]>dis[k]+w[i])
          {
            dis[v]=dis[k]+w[i];
            pre[v]=i;info[v]=Mn(info[k],cap[i]);
            if(!ins[v])q.push(v),ins[v]=1;
          }
        }
      return info[t];
    }
    int dfs(int cr)//for cr!=0 flow must be 1
    {
      if(cr==t)return 1; ins[cr]=1;
      for(int& i=cur[cr],v,tmp;i;i=nxt[i])
        if(!ins[v=to[i]]&&cap[i]&&dis[v=to[i]]==dis[cr]+w[i])
          if(tmp=dfs(v)){ans+=w[i];cap[i]--;cap[i^1]++;return 1;}
      return 0;
    }
    void MCMF()
    {
      int tmp;
      while(spfa())
        {
          memcpy(cur,hd,sizeof hd);
          while(tmp=dfs(0))flow+=tmp;
        }
    }
    int main()
    {
      n=rdn();m=rdn();t=1;
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++,t+=4)bh[i][j]=t;
      init();  if(val&1){puts("-1");return 0;}//
      MCMF();  printf("%d
    ",flow<<1==val?ans:-1);///
      return 0;
    }
    View Code
  • 相关阅读:
    prefixspan python
    python avro 数据格式使用demo
    UEBA 学术界研究现状——用户行为异常检测思路:序列挖掘prefixspan,HMM,LSTM/CNN,SVM异常检测,聚类CURE算法
    Dropout, DropConnect ——一个对输出,一个对输入
    成都Uber优步司机奖励政策(4月12日)
    北京Uber优步司机奖励政策(4月12日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(4月12日)
    MYSQL--慢查询,卡死等处理
    记boost在gcc的一个库链接问题generic_category()
    Linux生成core文件、core文件路径设置
  • 原文地址:https://www.cnblogs.com/Narh/p/10159227.html
Copyright © 2020-2023  润新知