【多题合集】网络流24题练习(更新至魔术球问题)

来源:互联网 发布:snmp linux版本查询 编辑:程序博客网 时间:2024/06/13 22:45

飞行员配对问题(仅求方案总数)
传送门
思路:二分图后dinic走起,各边容量为1
代码:

#include<bits/stdc++.h>#define inf 0x7ffusing namespace std;int ans,n,n1,s,t,tot=1;int first[105],dis[105],up[105];bool vis[105];queue<int>q;struct edge{    int u,v,next,w;}e[500];void add(int x,int y,int z){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].next=first[x];    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    memset(up,0,sizeof(up));    dis[s]=1;    q.push(s);    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)            if (!dis[e[i].v]&&e[i].w)                q.push(e[i].v),                dis[e[i].v]=dis[k]+1;    }    return dis[t];}void flow(){    int minn=0x7ff;    for (int i=up[t];i;i=up[e[i].u])    minn=min(minn,e[i].w);    ans+=minn;    for (int i=up[t];i;i=up[e[i].u])    e[i].w-=minn,e[i^1].w+=minn;}void dfs(int x,int maxn){    if (x==t) {flow();return;}    for (int i=first[x];i;i=e[i].next)    if (e[i].w&&dis[e[i].v]==dis[x]+1)    up[e[i].v]=i,dfs(e[i].v,min(maxn,e[i].w));}main(){    scanf("%d%d",&n,&n1);    int x,y;    s=n+1;t=n+2;        while (scanf("%d%d",&x,&y)!=EOF)        add(x,y,1),        add(y,x,0),        vis[x]=1;    for (int i=1;i<=n;i++)    if (vis[i]) add(s,i,1),add(i,s,0);    else add(i,t,1),add(t,i,0);    while (bfs())    dfs(s,0x7ff);    printf("%d",ans);}

太空飞行计划
传送门
思路:(在codevs上调了好久,最终弃疗)
cogs上是不用输出收益为0方案,所以我们直接学习了最大权闭合子图的姿势,求出最大流,并用所有点的正权值减去它就可以了
代码:

#include<bits/stdc++.h>#define inf 0x7fffffusing namespace std;int ans,n,m,tot=1,s,t;int first[205],dis[205],up[205];bool mac[102],exps[102];queue<int>q;struct edge{    int u,v,w,next;}e[40000];void add(int x,int y,int z){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].next=first[x];    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    memset(up,0,sizeof(up));    q.push(s);    dis[s]=1;    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)        if (e[i].w&&!dis[e[i].v])            dis[e[i].v]=dis[k]+1,q.push(e[i].v);    }    return dis[t];}void flow(){    int minn=inf;    for (int i=up[t];i;i=up[e[i].u])        minn=min(minn,e[i].w);    ans-=minn;    for (int i=up[t];i;i=up[e[i].u])        e[i].w-=minn,        e[i^1].w+=minn;}void dfs(int x,int maxn){    if (x==t) {flow();return;}    for (int i=first[x];i;i=e[i].next)    if (e[i].w&&dis[e[i].v]==dis[x]+1)        up[e[i].v]=i,dfs(e[i].v,min(maxn,e[i].w));}main(){    scanf("%d%d",&m,&n);    s=m+n+1;t=m+n+2;    int x;    for (int i=1;i<=m;i++)    {        scanf("%d",&x);        ans+=x;        add(s,i+n,x);        add(i+n,s,0);        while (1)        {            scanf("%d",&x);            add(i+n,x,inf);            add(x,i+n,0);            if (getchar()!=' ') break;        }    }    for (int i=1;i<=n;i++)        scanf("%d",&x),add(i,t,x),add(t,i,0);    while (bfs()) dfs(s,inf);    for (int i=first[s];i;i=e[i].next)        if (dis[e[i].v]) exps[e[i].v-n]=1;    for (int i=first[t];i;i=e[i].next)        if (dis[e[i].v]) mac[e[i].v]=1;    for (int i=1;i<=m;i++)        if (exps[i]) printf("%d ",i);    puts("");    for (int i=1;i<=n;i++)        if (mac[i]) printf("%d ",i);    puts("");    printf("%d",ans);}

圆桌问题
传送门
思路:这个构图太简单……不说了
注意:
1.时间上的优化!我之前写的这些都是扯淡!
2.别上codevs评测,没有SPJ
代码:

#include<bits/stdc++.h>using namespace std;int n,m,s,t,tot=1,ans,sum;int first[500],dis[500],num[500][500],up[500],cur[500],cnt[500];queue<int>q;struct edge{    int u,v,next,w;}e[100000];void add(int x,int y,int z){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].next=first[x];    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    dis[s]=1;    q.push(s);    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)            if (!dis[e[i].v]&&e[i].w) dis[e[i].v]=dis[k]+1,q.push(e[i].v);    }    if (dis[t])        for (int i=1;i<=t;i++) cur[i]=first[i];    return dis[t];}void flow(){    int minn=0x7fffff;    for (int i=up[t];i;i=up[e[i].u]) minn=min(minn,e[i].w);    if (!minn) return;    ans+=minn;    for (int i=up[t];i;i=up[e[i].u])    {        e[i].w-=minn;e[i^1].w+=minn;        if (e[i].u<=m&&e[i].v<=n+m)            num[e[i].u][e[i].v-m]^=1;        else if (e[i].v<=m&&e[i].u<=n+m)            num[e[i].v][e[i].u-m]^=1;    }}int dfs(int x,int maxn){    if (x==t) {flow();return maxn;}    int used=0;    for (int i=cur[x];i;i=e[i].next)    if (dis[e[i].v]==dis[x]+1)    {        up[e[i].v]=i;         int flow=dfs(e[i].v,min(maxn,e[i].w));        used+=flow;        if (e[i].w) cur[x]=i;        if (used==maxn) return maxn;    }    return used; }main(){    scanf("%d%d",&m,&n);    int x;    s=n+m+1;t=n+m+2;    for (int i=1;i<=m;i++)        scanf("%d",cnt+i),        sum+=cnt[i],        add(s,i,cnt[i]),        add(i,s,0);    for (int i=1;i<=n;i++)        scanf("%d",&x),        add(i+m,t,x),        add(t,i+m,0);    for (int i=1;i<=m;i++)        for (int j=1;j<=n;j++)            add(i,j+m,1),            add(j+m,i,0);    while (bfs()) dfs(s,0x7ffff);    if (ans<sum) {printf("0");return 0;}    puts("1");    for (int i=1;i<=m;i++)    {        for (int j=1;j<=n;j++)        if (num[i][j]) printf("%d ",j);        puts("");    }}

最长上升子序列问题
传送门
思路:发现网上大部分都是最大流拆点,而我写了个半残的费用流……
1.s->i连容量为1,费用为-1的边
2.i->t连容量为1,费用为0的边
3.i->j(a[i]<a[j])连容量为1,费用为-1的边
跑最小费用即可,算长度的话只用记录每次增广路上的费用总和就行了(不要乘流量,单算费用)
不用DP干掉1,2问
第3问把s->1,s->n,1->t,n->t的边容量无穷大就行了
注意:

求的是最长不下降子序列!不是最长上升子序列!这里坑爆了!

#include<bits/stdc++.h>using namespace std;int n,a[510],s,t,tot=1,len,ans=1;int first[510],up[510],dis[510];bool vis[510];queue<int> q;struct edge{    int u,v,w,next,cost;}e[200000];void add(int x,int y,int z,int c){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].cost=c;    e[tot].next=first[x];    first[x]=tot;}bool spfa(){    memset(dis,63,sizeof(dis));    memset(up,0,sizeof(up));    dis[s]=0;vis[s]=1;    q.push(s);    while (!q.empty())    {        int k=q.front();        q.pop();        vis[k]=0;        for (int i=first[k];i;i=e[i].next)        if (e[i].w&&dis[e[i].v]>dis[k]+e[i].cost)        {            dis[e[i].v]=dis[k]+e[i].cost;            up[e[i].v]=i;            if (!vis[e[i].v]) vis[e[i].v]=1,q.push(e[i].v);        }    }    return dis[t]<0x7ffff;}int flow(){    int p=0,minn=0x7fffff;    for (int i=up[t];i;i=up[e[i].u])        minn=min(e[i].w,minn),        p+=e[i].cost;    for (int i=up[t];i;i=up[e[i].u])        e[i].w-=minn,        e[i^1].w+=minn;    return p;}main(){    scanf("%d",&n);    s=n+1;t=n+2;    for (int i=1;i<=n;i++)    {        scanf("%d",a+i);        add(s,i,1,-1);        add(i,s,0,1);        add(i,t,1,0);        add(t,i,0,0);        for (int j=1;j<i;j++)            if (a[j]<=a[i])                add(j,i,1,-1),                add(i,j,0,1);    }    for (int i=tot+1;i<=tot*2;i++) e[i]=e[i-tot];    while (spfa())    {        if (!len) len=flow();        else if (len!=flow()) break;        else ans++;    }    printf("%d\n%d\n",-len,ans);    for (int i=1;i<=tot;i++)    {        e[i]=e[i+tot];        if ((e[i].u==s&&e[i].v==n)||(e[i].u==s&&e[i].v==1)) e[i].w=0x7ff;        if ((e[i].u==n&&e[i].v==t)||(e[i].u==1&&e[i].v==t)) e[i].w=0x7ff;    }    ans=1;len=0;    while (spfa())    {        if (!len) len=flow();        else if (len!=flow()) break;        else ans++;    }    printf("%d",ans);}

最小路径覆盖问题
传送门
思路:
二分图最大流,答案=点数-流量和
方案数从1-n枚举dfs找路径即可,要求流量为0
注意:输出格式注意!最后要换行!codevs上只用输出方案数!

#include<bits/stdc++.h>using namespace std;int n,m,tot=1,s,t;int first[320],dis[320],cur[320],ans;int num[320];bool vis[320];queue<int>q;struct edge{    int u,v,w,next;}e[15000];void add(int x,int y,int z){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].next=first[x];    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    dis[s]=1;    q.push(s);    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)        if (e[i].w&&!dis[e[i].v])            dis[e[i].v]=dis[k]+1,            q.push(e[i].v);    }    if (dis[t])        for (int i=1;i<=t;i++) cur[i]=first[i];    return dis[t];}int dfs(int x,int maxn){    if (x==t) {return maxn;}    int used=0;    for (int i=cur[x];i;i=e[i].next)    if (dis[e[i].v]==dis[x]+1)    {        int k=dfs(e[i].v,min(maxn,e[i].w));        e[i].w-=k;e[i^1].w+=k;        used+=k;        if (e[i].w) cur[x]=i;        if (used==maxn) return maxn;    }    if (!used) dis[x]=0;    return used;}void find(int x){    num[++num[0]]=x;    vis[x]=1;    for (int i=first[x];i;i=e[i].next)    if (!e[i].w&&e[i].v!=s&&!vis[e[i].v-n]) find(e[i].v-n);}main(){    freopen("path3.in","r",stdin);    freopen("path3.out","w",stdout);    scanf("%d%d",&n,&m);    int x,y;    for (int i=1;i<=m;i++)        scanf("%d%d",&x,&y),        add(x,y+n,1),        add(y+n,x,0);    s=(n<<1)+1;t=n+1<<1;    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);    while (bfs())    ans+=dfs(s,0x7ff);    for (int i=1;i<=n;i++)        if (!vis[i])        {            num[0]=0,find(i);            for (int i=1;i<=num[0];i++)            printf("%d%c",num[i]," \n"[i==num[0]]);        }    printf("%d\n",n-ans);}

餐巾计划问题
传送门1
传送门2
思路:
感觉好厉害,一开始没有考虑流量守恒,建图完全错了,该连源点的连汇点,该连汇点的连了源点(s连新餐巾,t连旧餐巾)然后就一直买啊买也不洗……改一下就连买都不买了……后来看了高大哥的课件建图,感觉自己还是功力不深啊!!
这里写图片描述
代码:

#include<bits/stdc++.h>#define inf 0x7ffffusing namespace std;int n,f,c1,c2,t1,t2,s,t,tot=1,ans;bool vis[2010];int dis[2010],first[2010],up[2010];queue<int>q;struct edge{    int u,v,w,cost,next;}e[200000];void add(int x,int y,int z,int c){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].cost=c;    e[tot].next=first[x];    first[x]=tot;}bool spfa(){    memset(dis,63,sizeof(dis));    memset(up,0,sizeof(up));    q.push(s);    dis[s]=0;vis[s]=1;    while (!q.empty())    {        int k=q.front();        q.pop();        vis[k]=0;        for (int i=first[k];i;i=e[i].next)            if (e[i].w&&dis[e[i].v]>dis[k]+e[i].cost)            {                dis[e[i].v]=dis[k]+e[i].cost;                up[e[i].v]=i;                if (!vis[e[i].v]) vis[e[i].v]=1,q.push(e[i].v);            }    }    return dis[t]<inf;}void flow(){    int minn=inf;    for (int i=up[t];i;i=up[e[i].u]) minn=min(e[i].w,minn);    for (int i=up[t];i;i=up[e[i].u])        e[i].w-=minn,        e[i^1].w+=minn,        ans+=minn*e[i].cost;}main(){//  scanf("%d%d%d%d%d%d",&n,&f,&t1,&c1,&t2,&c2);codevs上的//  scanf("%d%d%d%d%d%d",&n,&t1,&t2,&f,&c1,&c2);//  t1++;t2++;BZOJ上的    s=(n<<1)+1;t=1+n<<1;    int x;    for (int i=1;i<=n;i++)    {        scanf("%d",&x);        add(i+n,t,x,0);        add(t,i+n,0,0);        add(s,i,x,0);        add(i,s,0,0);        add(s,i+n,inf,f);        add(i+n,s,0,-f);        if (i+1<=n) add(i,i+1,inf,0),add(i+1,i,0,0);        if (i+t1<=n) add(i,i+t1+n,inf,c1),add(i+t1+n,i,0,-c1);        if (i+t2<=n) add(i,i+t2+n,inf,c2),add(i+t2+n,i,0,-c2);    }    while (spfa()) flow();    printf("%d",ans);}

星际转移问题(家园)
传送门1
传送门2
思路:数据比较小,可以枚举时间动态开点连边,把图分层,各个太空站在每一个时刻都是一个独立的点,样例中的
2 2 1
1 3 0 1 2
1 3 1 2 –1
构图为这样(没有连边的原因是画出来就很乱,所以不连了)
这里写图片描述
如果我们把时刻为t时的i点标号为st[t][i]且在这个飞船的下一站为next[i],我们要连的就是(st[t][i],st[t+1][next[i]])
同时,每个太空站是可以留人的,所以还要连(st[t][i],st[t+1][i]
然后枚举时间由1->+∞跑最大流,当总流量>=t时就可以停下了
注意:
1.我们不可能一直把时间枚举下去,差不多t=500(可能更小)的时候就可以停下输出无解了
2.给点标号着实让我蛋疼了好久,大家自己感受下吧

#include<bits/stdc++.h>#define inf 0x7fffusing namespace std;int ans,times,n,m,k,tot=1,s,t;int cur[5000],dis[5000],first[5000],p[30],st[30][17],num[30];queue<int>q;struct edge{    int u,v,w,next;}e[20000];void add(int x,int y,int z){    e[++tot].u=x;    e[tot].v=y;    e[tot].w=z;    e[tot].next=first[x];    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    q.push(s);dis[s]=1;    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)        if (!dis[e[i].v]&&e[i].w)            dis[e[i].v]=dis[k]+1,q.push(e[i].v);    }    cur[s]=first[s];cur[t]=first[t];    if (dis[t]) for (int i=1;i<=times*m;i++) cur[i]=first[i];    return dis[t];}int dfs(int x,int maxn){    if (x==t) return maxn;    int used=0;    for (int i=cur[x];i;i=e[i].next)    if (dis[e[i].v]==dis[x]+1)    {        int k=dfs(e[i].v,min(maxn,e[i].w));        used+=k;        e[i].w-=k;        e[i^1].w+=k;        if(e[i].w) cur[x]=i;        if (used==maxn) return maxn;    }if (!used) dis[x]=0;    return used;}main(){    scanf("%d%d%d",&n,&m,&k);    s=4999;t=4998;    for (int i=1;i<=m;i++)    {        scanf("%d%d",p+i,num+i);        for (int j=0;j<num[i];j++)        {            scanf("%d",st[i]+j);            if (st[i][j]<=0) st[i][j]+=4999;        }    }    while (++times<=500)    {        for (int i=1;i<=m;i++)        {            int x,y;            if (st[i][(times-1)%num[i]]==s) x=s;            else if (st[i][(times-1)%num[i]]==t) x=t;            else x=st[i][(times-1)%num[i]]+n*(times-1);            if (st[i][times%num[i]]==s) y=s;            else if (st[i][times%num[i]]==t) y=t;            else y=st[i][times%num[i]]+n*times;            add(x,y,p[i]);            add(y,x,0);        }        for (int i=n*(times-1)+1;i<=n*(times-1)+n;i++)            add(i,i+n,inf),add(i+n,i,0);        while (bfs()) ans+=dfs(s,0x7ff);        if (ans>=k) printf("%d",times),exit(0);    }    printf("0");}

骑士共存问题
传送门
思路:根据所在行列之和x+y的奇偶来进行二分图,然后跑dinic
s->奇 容量为1
偶数->t 容量为1
奇数->被他影响的8个点 容量为inf
最后得出的最大流就是放完最多数后的不能放的点(不包括m个点),答案就是n*n-m-maxflow
代码:

#include<bits/stdc++.h>#define inf 0x7ffff#define pd(x,y,z) (x<=y&&y<=z)using namespace std;int ans,s,t,n,m,x,y,tot=1;int dis[80010],first[80010],cur[80010];int dx[9]={0,-1,-2,-2,-1,1,2,2,1},dy[9]={0,-2,-1,1,2,-2,-1,1,2};bool vis[80010];queue<int>q;struct edge{    int u,v,w,next;}e[410000];void add(int x,int y,int z){    e[++tot]=(edge){x,y,z,first[x]};    first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    q.push(s);dis[s]=1;    while (!q.empty())    {        int k=q.front();        q.pop();        for (int i=first[k];i;i=e[i].next)            if (e[i].w&&!dis[e[i].v])                q.push(e[i].v),dis[e[i].v]=dis[k]+1;    }    if (dis[t])        for (int i=1;i<=t;i++) cur[i]=first[i];    return dis[t];}int dfs(int x,int maxn){    if (x==t) return maxn;    int used=0;    for (int i=cur[x];i;i=e[i].next)    if (dis[e[i].v]==dis[x]+1)    {        int k=dfs(e[i].v,min(maxn,e[i].w));        e[i].w-=k;        e[i^1].w+=k;        if (e[i].w) cur[x]=i;        used+=k;        if (used==maxn) return maxn;    }    if (!used) dis[x]=0;    return used;}main(){    scanf("%d%d",&n,&m);    for (int i=1;i<=m;i++)        scanf("%d%d",&x,&y),        vis[(x-1)*n+y]=1;    s=n*n+1;t=n*n+2;    for (int i=1;i<=n;i++)        for (int j=1;j<=n;j++)        if (!vis[(i-1)*n+j])        {            x=(i-1)*n+j;            if ((i+j)&1)            {                add(s,x,1);add(x,s,0);                for (int k=1;k<=8;k++)                if (pd(1,i+dx[k],n)&&pd(1,j+dy[k],n))                    add(x,n*(i+dx[k]-1)+j+dy[k],inf),                    add(n*(i+dx[k]-1)+j+dy[k],x,0);            }            else add(x,t,1),add(t,x,0);        }    while (bfs())        ans+=dfs(s,inf);    printf("%d",n*n-ans-m);}

魔术球问题(简化版)
传送门
思路:枚举答案,动态加点判断,但一开始我是暴力加边,多建了一层关于“柱子”的点,只过了9个点,后来看到黄学长的blog才幡然醒悟,合并点,这里直接求最小路径覆盖就好了,每次加入一个待放的球,跑最大流,判断一下,如果它不能归到之前的路径上就让ans++,直到ans>n
注意:codevs上没有SPJ,但要输出方案数!

#include<bits/stdc++.h>using namespace std;int n,s,t,tot=1,ans=1;struct edge{    int u,v,w,next;}e[200000];int first[3500],dis[3500];bool sr[3204];queue<int>q;void add(int x,int y,int z){e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    q.push(s);dis[s]=1;    while (!q.empty())    {        int k=q.front();        for (int i=first[k];i;i=e[i].next)        if (e[i].w&&!dis[e[i].v])            q.push(e[i].v),dis[e[i].v]=dis[k]+1;        q.pop();    }    return dis[t];}int dfs(int x,int maxn){    if (x==t) return maxn;    int used=0;    for (int i=first[x];i;i=e[i].next)        if (dis[e[i].v]==dis[x]+1)        {            int k=dfs(e[i].v,min(maxn,e[i].w));            e[i].w-=k;e[i^1].w+=k;            used+=k;            if (used==maxn) return maxn;        }    if (!used) dis[x]=0;    return used;}main(){    freopen("balla.in","r",stdin);    freopen("balla.out","w",stdout);    for (int i=1;i<=56;i++) sr[i*i]=1;    t=3244;    scanf("%d",&n);    for (int i=1;i<=1600;i++,ans++)    {        add(s,i,1);add(i,s,0);        for (int j=1;j<i;j++)            if (sr[j+i]) add(j,i+1600,1),add(i+1600,j,0);        add(i+1600,t,1);        add(t,i+1600,0);        while (bfs()) ans-=dfs(s,0x7f);        if (ans>n) {ans=i;break;}    }    printf("%d",ans-1);}

方格取数问题
传送门
思路:二分图染黑白,然后就是求最大权闭合子图了,可以参照上面的太空飞行计划,流量就是点的权值
不过这道题好坑啊,之前的最大流方法总会WA三个点,只能用回最暴力的dfs单线跑流了
代码:

#include<bits/stdc++.h>#define inf 0x7fffff#define pd(x,y,z) (x<=y&&y<=z)using namespace std;int n,m,s,t,tot=1,sum,ans;int dis[1000],first[1000],cur[1000],up[1000];int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};queue<int>q;struct edge{    int u,v,w,next;}e[10000];void add(int x,int y,int z) {e[++tot]=(edge){x,y,z,first[x]};first[x]=tot;}bool bfs(){    memset(dis,0,sizeof(dis));    dis[s]=1;q.push(s);    while (!q.empty())    {        int k=q.front();        for (int i=first[k];i;i=e[i].next)            if (e[i].w&&!dis[e[i].v])                q.push(e[i].v),dis[e[i].v]=dis[k]+1;        q.pop();    }    if (dis[t])        for (int i=s;i<=t;i++) cur[i]=first[i];    return dis[t];}void flow(){    int minn=inf;    for (int i=up[t];i;i=up[e[i].u])    minn=min(minn,e[i].w);    ans+=minn;    for (int i=up[t];i;i=up[e[i].u])    e[i].w-=minn,e[i^1].w+=minn;}void dfs(int x,int maxn){    if (x==t) {flow();return;}    for (int i=first[x];i;i=e[i].next)    if (e[i].w&&dis[e[i].v]==dis[x]+1)    up[e[i].v]=i,dfs(e[i].v,min(maxn,e[i].w));}main(){    scanf("%d%d",&n,&m);    int x;    t=n*m+1;    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)        {            scanf("%d",&x);            sum+=x;            if (((i+j)&1))            {                add(s,m*(i-1)+j,x);                add(m*(i-1)+j,s,0);                for (int k=0;k<4;k++)                    if(pd(1,i+dx[k],n)&&pd(1,j+dy[k],m))                        add(m*(i-1)+j,m*(i-1+dx[k])+j+dy[k],inf),                        add(m*(i-1+dx[k])+j+dy[k],m*(i-1)+j,0);            }            else add(m*(i-1)+j,t,x),add(t,m*(i-1)+j,0);        }    while (bfs()) dfs(s,inf);    printf("%d",sum-ans);}
0 0
原创粉丝点击