zoukankan      html  css  js  c++  java
  • [专题总结]网络流初步(2)

    通过颓了一个题解,终于也搞定了这个专题。

    大神都颓题解。

              ——By skyh

    无限之环

    颓题解就行了。

    建图是真的恶心。不很好想。

    还是自己想到了一部分,就是看到题目里说“直线形不能转”就感觉要分类讨论。

    无非就那么几类:空格,单个管,L型,直线型,T型,十字形

    我一直以为这道题是最小割,然后我就死掉了,思维僵化,实际上这道题是费用流。

    惯性拆点,每个点拆成5个,分别是原点以及四个方向。

    而且还要染色,就是那种棋盘黑白染色。

    根据水管最开始的方向,将原点与剩下的4个点连边。并且根据黑白颜色讲源汇与原点连边。(我是白连源黑连汇)

    然后考虑旋转,分类讨论:

    单个管:这个好说,讲原有方向分别向其它方向连边,对立方向费用为2其余费用为1。

    L型:它有3种旋转,改变一个支管的方向费用为1,全都改变为2,所以关键就在于改变了几个管。

      以上右为例,上向下连1费用边,右向左连1费用边,这样就做到了上述要求。(注意不能是上向左,下向右,考虑实际含义)

    直线型:不能旋转,不连边

    T型:和单个管差不多。

    十字型:不用连。

    这样的话,黑白染色之后跑流,如果流量==水管接头个数/2,那么就有解,就输出最小费用,否则0。

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 const int xx[]={-1,0,1,0},yy[]={0,1,0,-1};
     5 #define X i+xx[p]
     6 #define Y j+yy[p]
     7 #define S 1000005
     8 #define k knd[i][j]
     9 #define O o[i][j]
    10 #define Q i+j&1^1
    11 int l[S],to[S],v[S],w[S],fir[S],o[2002][2002][5],ec=1,pc,n,m,E,tot,knd[2005][2005],ans;
    12 int d[S],pre[S],q[S],iq[S];
    13 void link(int a,int b,int V,int W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;}
    14 void con(int a,int b,int V,int W,int opt=0){if(opt)a^=b^=a^=b;link(a,b,V,W);link(b,a,0,-W);}
    15 bool SPFA(){
    16     for(int i=1;i<=E;++i)d[i]=S;
    17     for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(d[to[i]]>d[q[h]]+w[i]&&v[i]){
    18         d[to[i]]=d[q[h]]+w[i];pre[to[i]]=i;
    19         if(!iq[to[i]])iq[q[++t]=to[i]]=1;
    20     }return d[E]<S;
    21 }
    22 int main(){
    23     scanf("%d%d",&n,&m);
    24     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int p=0;p<=4;++p)o[i][j][p]=++pc;
    25     E=++pc;
    26     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(i+j&1)con(0,O[0],4,0);else con(O[0],E,4,0);
    27     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)scanf("%d",&k);
    28     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int s=0;s<4;++s)if(k&1<<s)con(O[0],O[s+1],1,0,Q),tot++;
    29     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){
    30         if(k== 1)con(O[1],O[2],1,1,Q),con(O[1],O[3],1,2,Q),con(O[1],O[4],1,1,Q);
    31         if(k== 2)con(O[2],O[1],1,1,Q),con(O[2],O[3],1,1,Q),con(O[2],O[4],1,2,Q);
    32         if(k== 4)con(O[3],O[2],1,1,Q),con(O[3],O[4],1,1,Q),con(O[3],O[1],1,2,Q);
    33         if(k== 8)con(O[4],O[2],1,2,Q),con(O[4],O[3],1,1,Q),con(O[4],O[1],1,1,Q);
    34         if(k== 3)con(O[2],O[4],1,1,Q),con(O[1],O[3],1,1,Q);
    35         if(k== 6)con(O[3],O[1],1,1,Q),con(O[2],O[4],1,1,Q);
    36         if(k==12)con(O[4],O[2],1,1,Q),con(O[3],O[1],1,1,Q);
    37         if(k== 9)con(O[1],O[3],1,1,Q),con(O[4],O[2],1,1,Q);
    38         if(k==14)con(O[2],O[1],1,1,Q),con(O[4],O[1],1,1,Q),con(O[3],O[1],1,2,Q);
    39         if(k==13)con(O[3],O[2],1,1,Q),con(O[1],O[2],1,1,Q),con(O[4],O[2],1,2,Q);
    40         if(k==11)con(O[2],O[3],1,1,Q),con(O[4],O[3],1,1,Q),con(O[1],O[3],1,2,Q);
    41         if(k== 7)con(O[1],O[4],1,1,Q),con(O[3],O[4],1,1,Q),con(O[2],O[4],1,2,Q);
    42     }
    43     for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)for(int p=0;p<4;++p)if(1<=X&&X<=n&&1<=Y&&Y<=m)
    44         con(O[p+1],o[X][Y][(p^2)+1],1,0);
    45     while(SPFA()){tot-=2;for(int i=pre[E];i;i=pre[to[i^1]])ans+=w[i],v[i]--,v[i^1]++;}
    46     printf("%d
    ",tot?-1:ans);
    47 }
    代码感人

    星际竞速

    上下界无源汇最小费用可行流板子。

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 #define E 2*n+1
     5 #define S 2*n+2
     6 #define Q 333333
     7 int n,m,fir[Q],l[Q],to[Q],v[Q],w[Q],ec=1,C,q[Q],d[Q],iq[Q],pre[Q];
     8 void link(int a,int b,int V,int W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;}
     9 bool SPFA(){
    10     for(int i=1;i<=S;++i)d[i]=0x3fffffff;
    11     for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&d[to[i]]>d[q[h]]+w[i]){
    12         d[to[i]]=d[q[h]]+w[i];pre[to[i]]=i;
    13         if(!iq[to[i]])iq[q[++t]=to[i]]=1;
    14     }return d[E]<0x3fffffff;
    15 }
    16 int main(){
    17     scanf("%d%d",&n,&m);
    18     link(0,S,1,0);link(S,0,0,0);
    19     for(int i=1,x;i<=n;++i)scanf("%d",&x),
    20         link(S,i,1,x),link(i,S,0,-x),link(i+n,S,1,0),link(S,i+n,0,0),
    21         link(i,E,1,0),link(E,i,0,0),link(0,i+n,1,0),link(i+n,0,0,0);
    22     for(int i=1,a,b,c;i<=m;++i){
    23         scanf("%d%d%d",&a,&b,&c);if(a>b)a^=b^=a^=b;
    24         link(a+n,b,1,c);link(b,a+n,0,-c);
    25     }
    26     while(SPFA())for(int i=pre[E];i;i=pre[to[i^1]])C+=w[i],v[i]--,v[i^1]++;
    27     printf("%d
    ",C);
    28 }
    View Code

    千钧一发

    看起来很像《数字配对》?然后我又用鬼畜的联动边权解决了。

    尝试,看那两个条件,想(很长)一段时间,就知道可以按照奇偶性分成二分图。

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<iostream>
     4 using namespace std;
     5 #define M 1000000000
     6 #define E 2*n+1
     7 int a[2005],b[2005],n,ec=3,ans,q[2005],d[2005],fir[2005],l[2000005],to[2000005],v[2000005];
     8 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;}
     9 bool bfs(){
    10     for(int i=1;i<=E;++i)d[i]=0;
    11     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&!d[to[i]])
    12         d[q[++t]=to[i]]=d[q[h]]+1;
    13     return d[E];
    14 }
    15 int dfs(int p,int flow){
    16     if(p==E)return flow;int r=flow;
    17     for(int i=fir[p];i;i=l[i])if(v[i]&&d[to[i]]==d[p]+1&&r){
    18         int x=dfs(to[i],min(v[i],r));
    19         if(!x)d[to[i]]=0;
    20         v[i]-=x;v[i^1]+=x,v[i^2]-=x;v[i^3]+=x;r-=x;
    21     }return flow-r;
    22 }
    23 bool ju(long long x){int p=sqrt(x);return 1ll*p*p==x;}
    24 int gcd(int a,int b){return b?gcd(b,a%b):a;}
    25 int main(){
    26     scanf("%d",&n);d[0]=1;
    27     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    28     for(int i=1;i<=n;++i)scanf("%d",&b[i]),ans+=b[i];
    29     for(int i=1;i<=n;++i)link(0,i,b[i]),link(i,0,0),link(n+i,E,b[i]),link(E,n+i,0);
    30     for(int i=1;i<=n;++i)for(int j=i+1;j<=n;++j)if(ju(1ll*a[i]*a[i]+1ll*a[j]*a[j])&&gcd(a[i],a[j])==1)
    31         link(i,j+n,M),link(j+n,i,0),link(j,i+n,M),link(i+n,j,0);
    32     while(bfs())ans-=dfs(0,M);printf("%d
    ",ans);
    33 }
    View Code

    老C的方块

    LNC大喊标签被我听到了,然后稍微想一下就会了。

    观察,只有竖线没有横线,也许可用?

    再发现,他讨厌的图形都被竖线劈成两半,左右都是2个方块。

    再发现,其实就是左边距离为2,1,右边距离为1,2的4个点构成一个讨厌的图形。

    最小割。四色染色。

    这样编号后,所有讨厌的图形都可以表示为ABCD。然后建四分图就好了。

     1 #include<cstdio>
     2 #include<map>
     3 using namespace std;
     4 map<pair<int,int>,int>M;
     5 const int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
     6 #define tx X[i]+dx[j]
     7 #define ty Y[i]+dy[j]
     8 #define inf 0x3fffffff
     9 #define S 13333333
    10 int r,c,n,X[S],Y[S],C[S],ans,fir[S],l[S],to[S],v[S],ec=1,d[S],q[S];
    11 int knd(int x,int y){return x&1?y&3:1000005-y&3;}
    12 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;}
    13 void con(int a,int b,int V){link(a,b,V);link(b,a,0);}
    14 bool bfs(){
    15     for(int i=1;i<=(n<<1|1);++i)d[i]=0;
    16     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&!d[to[i]])
    17         d[q[++t]=to[i]]=d[q[h]]+1;
    18     return d[1];
    19 }
    20 int dfs(int p,int flow){
    21     int r=flow;if(p==1)return r;
    22     for(int i=fir[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+1){
    23         int x=dfs(to[i],min(v[i],r));
    24         if(!x)d[to[i]]=0;
    25         v[i]-=x;v[i^1]+=x;r-=x;
    26     }return flow-r;
    27 }
    28 int main(){
    29     scanf("%d%d%d",&r,&c,&n);d[0]=1;
    30     for(int i=1;i<=n;++i)scanf("%d%d%d",&Y[i],&X[i],&C[i]),M[make_pair(X[i],Y[i])]=i;
    31     for(int i=1;i<=n;++i)con(i<<1,i<<1|1,C[i]);
    32     for(int i=1;i<=n;++i)if(!knd(X[i],Y[i]))con(0,i<<1,inf);
    33         else for(int j=0;j<4;++j)if(M[make_pair(tx,ty)]&&knd(tx,ty)==knd(X[i],Y[i])-1)con(M[make_pair(tx,ty)]<<1|1,i<<1,inf);
    34     for(int i=1;i<=n;++i)if(knd(X[i],Y[i])==3)con(i<<1|1,1,inf);
    35     while(bfs())ans+=dfs(0,inf);printf("%d
    ",ans);
    36 }
    View Code

    线性代数

    解出来,发现式子的含义就是$sumlimits A_i imes A_j imes B_{i,j} - sumlimits C_i imes A_i$

    选一个数付出C代价,同时选得到B收益。

    暴力。

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define M 40000000
     5 int n,fir[255555],l[1555555],to[1555555],v[1555555],q[1555555],d[1555555],E,pc,ec=1;
     6 int B[555][555],C[555],ans;
     7 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;}
     8 void con(int a,int b,int V){link(a,b,V);link(b,a,V);}
     9 bool bfs(){
    10     for(int i=1;i<=E;++i)d[i]=0;
    11     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&!d[to[i]])
    12         d[q[++t]=to[i]]=d[q[h]]+1;
    13     return d[E];
    14 }
    15 int dfs(int p,int flow){
    16     int r=flow;if(p==E)return flow;
    17     for(int i=fir[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+1){
    18         int x=dfs(to[i],min(v[i],r));
    19         if(!x)d[to[i]]=0;
    20         v[i]-=x;v[i^1]+=1;r-=x;
    21     }return flow-r;
    22 }
    23 int main(){
    24     scanf("%d",&n);pc=n;E=n*n+n+1;
    25     for(int i=1;i<=n;++i)for(int j=1,x;j<=n;++j)scanf("%d",&B[i][j]),ans+=B[i][j];
    26     for(int i=1,x;i<=n;++i)scanf("%d",&x),con(0,i,x);
    27     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)link(i,++pc,M),link(j,pc,M),link(pc,E,B[i][j]);
    28     while(bfs())ans-=dfs(0,M);printf("%d
    ",ans);
    29 }
    View Code

    优化建边。

     1 #include<cstdio>
     2 #include<iostream>
     3 using namespace std;
     4 #define M 40000000
     5 #define E n+1
     6 int n,fir[255555],l[1555555],to[1555555],v[1555555],q[1555555],d[1555555],ec=1;
     7 int B[555][555],C[555],ans,b[555];
     8 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;}
     9 void con(int a,int b,int V){link(a,b,V);link(b,a,V);}
    10 bool bfs(){
    11     for(int i=1;i<=E;++i)d[i]=0;
    12     for(int h=1,t=1;h<=t;++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&!d[to[i]])
    13         d[q[++t]=to[i]]=d[q[h]]+1;
    14     return d[E];
    15 }
    16 int dfs(int p,int flow){
    17     int r=flow;if(p==E)return flow;
    18     for(int i=fir[p];i&&r;i=l[i])if(v[i]&&d[to[i]]==d[p]+1){
    19         int x=dfs(to[i],min(v[i],r));
    20         if(!x)d[to[i]]=0;
    21         v[i]-=x;v[i^1]+=1;r-=x;
    22     }return flow-r;
    23 }
    24 int main(){
    25     scanf("%d",&n);
    26     for(int i=1;i<=n;++i)for(int j=1,x;j<=n;++j)scanf("%d",&B[i][j]),ans+=B[i][j],b[i]+=B[i][j];
    27     for(int i=1,x;i<=n;++i)scanf("%d",&x),con(0,i,x),con(i,E,b[i]);
    28     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)con(i,j,B[i][j]);
    29     while(bfs())ans-=dfs(0,M);printf("%d
    ",ans);
    30 }
    View Code

    海拔

    猜测:你设置的高度只有0和1

    口胡证明:对于任意一个格子,它的高度值一定至少与上下左右四个格子之一相同,那样的话答案不会变差

    推下去,所以所有格子的高度要么和左上角相同,要么和右下角相同。

    现在的问题就是把每个点赋值0或1使答案尽量小。

    0和1一定都是一个联通块,不存在孤立的情况。否则把孤立的0或1变成另外一个数答案也不会变差。

    所以问题就是:将整个图分割为两个联通块。

    最小割。T90。

    发现是在二维平面上的,所以采取对偶图优化。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 using namespace std;
     5 priority_queue<pair<int,int> >q;
     6 #define M 4000000
     7 int n,pc,ec=1,E,fir[M],l[M],to[M],v[M],d[M],o[555][555];
     8 void link(int a,int b,int V){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;}
     9 int main(){
    10     scanf("%d",&n);
    11     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)o[i][j]=++pc,d[pc]=M<<7;d[E=++pc]=M<<7;
    12     for(int i=1;i<=n;++i)o[0][i]=o[i][n+1]=E;
    13     for(int i=0;i<=n;++i)for(int j=1,x;j<=n;++j)scanf("%d",&x),link(o[i+1][j],o[i][j],x);
    14     for(int i=1;i<=n;++i)for(int j=0,x;j<=n;++j)scanf("%d",&x),link(o[i][j],o[i][j+1],x);
    15     for(int i=0;i<=n;++i)for(int j=1,x;j<=n;++j)scanf("%d",&x),link(o[i][j],o[i+1][j],x);
    16     for(int i=1;i<=n;++i)for(int j=0,x;j<=n;++j)scanf("%d",&x),link(o[i][j+1],o[i][j],x);
    17     q.push(make_pair(0,0));
    18     while(!q.empty()){
    19         int p=q.top().second,dt=-q.top().first;q.pop();
    20         if(dt!=d[p])continue;
    21         for(int i=fir[p];i;i=l[i])if(d[to[i]]>dt+v[i])q.push(make_pair(-(d[to[i]]=dt+v[i]),to[i]));
    22     }printf("%d
    ",d[E]);
    23 }
    View Code
  • 相关阅读:
    dubbo No provider available for the service com.alibaba.dubbo.monitor.MonitorService from registry
    mvn install
    centos mysql 数据存储目录安装位置
    maven项目依赖被改为文件夹时如何改回lib
    Oracle 用户权限分配说明
    PowerDesigner中创建Oracle表全过程记录
    Oracle创建表时涉及的参数解析
    PowerDesigner使用技巧
    关于Web服务器域名设置相关知识积累
    【转载】错误:ORA-28002: the password will expire within 7 days 解决方法
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11979700.html
Copyright © 2011-2022 走看看