天天看点

网络流与线性规划二十四题

前言

网络流大法好

只刷了14道题目,剩下的真的做不动啦。

1.飞行员匹配问题

传送门

本题为二分图匹配问题,可以用网络流解决,也可以用匈牙利算法解决。

这题是一道SPJ,方案不唯一,样例好长时间不过,我以为我错了。。。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define il inline
using namespace std;
const int inf=;
const int maxm=+;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*];
int cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[maxm],id[maxm],match;
queue <int> dl;
il int BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    pre[s]=,flow[s]=inf;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        if(x==t) break;
        for(int i=head[x];i;i=net[i])
        if(to[i]!=s&&cap[i]>&&pre[to[i]]==-)
        {
            pre[to[i]]=x,id[to[i]]=i;
            flow[to[i]]=min(flow[x],cap[i]);
            dl.push(to[i]);
        }
    }
    if(pre[t]==-) return -;
    else return flow[t];
}
il void change_cap(int s,int t,int x)
{
    int now=t,last,sum=;
    while(now!=s)
    {
        cap[id[now]]-=x;
        cap[id[now]^]+=x;
        now=pre[now];
        //if((sum&1)==0) match[now]=last;
        //else last=now;
        //sum++;
    }
}
il int maxflow(int s,int t)
{
    int max_flow=;
    int d=;
    while((d=(BFS(s,t)))!=-)
    {
        change_cap(s,t,d);
        max_flow+=d;
    }
    return max_flow;
}
int main()
{
    int n,m,s,t;
    scanf("%d%d",&m,&n);
    s=,t=n+;
    int s1=,s2=;
    while()
    {
        scanf("%d%d",&s1,&s2);
        if(s1==-&&s2==-) break;
        add(s1,s2,inf),add(s2,s1,);
    }
    for(int i=;i<=m;i++) add(s,i,),add(i,s,);
    for(int i=m+;i<=n;i++) add(i,t,),add(t,i,);
    printf("%d\n",maxflow(s,t));
    for(int i=;i<=cnt;i+=)
    {
        s1=to[i],s2=to[i^];
        if(s1==s||s1==t||s2==s||s2==t) continue;
        if(cap[i^]) printf("%d %d\n",s2,s1);
    }
    return ;
}
           

2.软件补丁问题

传送门

神TM网络流。

SPFA+状压轻松水过

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
bool vis[<<];
int inf;
int ok1[],ok2[],help[],cas[],time[],dis[<<];
queue <int> dl;
int n,m;
char s[];
int spfa()
{
    memset(dis,/,sizeof(dis));
    dis[(<<n)-]=;
    vis[(<<n)-]=;
    inf=dis[];
    dl.push((<<n)-);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=;i<=m;i++)
        {
            bool f1=((ok1[i]&x)==ok1[i]),f2=((ok2[i]&x)==);
            if(!f1||!f2) continue;
            int to=x&(help[i]);
            to|=cas[i];
            if(dis[x]+time[i]<dis[to])
            {
                dis[to]=dis[x]+time[i];
                if(vis[to]) continue;
                vis[to]=,dl.push(to);
            }
        }
    }
    return dis[]==inf?:dis[];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=;i<=m;i++)
    {
        scanf("%d %s",&time[i],s);
        for(int j=;j<strlen(s);j++)
         {
            if(s[j]=='+') ok1[i]|=(<<j);
            if(s[j]=='-') ok2[i]|=(<<j);
         }
        scanf("%s",s);
        int l=,r=;
        for(int j=;j<strlen(s);j++)
         {
            if(s[j]=='-') l+=(<<j);
            if(s[j]=='+') r+=(<<j);
         }
        help[i]=~l,cas[i]=r;
    }
    //cout<<ok1[1]<<" "<<ok2[1]<<endl; 
    printf("%d\n",spfa()); 

    return ;
}
           

3.负载平衡问题

传送门

要不是这标签,打死我也不想最小费用最大流。

网络流之精髓,在于建模。

建模分析:

首先,我们先计算出平均的货物数量。

虚拟出一个源点和一个汇点。

将一个仓库拆成两个节点,供应节点X以及需求节点Y

从一个仓库的供应节点向相邻仓库的需求节点建立容量无限大,费用为1的边,模拟仓库之间的搬运。

从一个仓库的供应节点向相邻仓库的供应节点建立容量无限大,费用为1的边,模拟仓库之间的停留搬运

若一个仓库有盈余,则从源点向此仓库的供应节点建立容量为盈余,费用为0的边。

若一个仓库有亏损,则从此仓库的需求节点向汇点连一条容量为亏损,费用为0的边

在此网络上跑网络流,亏损和盈余之间会互补,此时求出的费用即为最小费用。

震惊的是:此题EK居然和Dinic一样快

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*],cost[maxm*];
int val[maxm];
int cnt=;
il void add(int x,int y,int c,int z){cnt++,to[cnt]=y,cost[cnt]=z,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[maxm],id[maxm],dis[maxm],max_flow,min_cost;
bool vis[maxm];
queue <int> dl;
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,/,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]>dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
il void change_cap(int s,int t,int x)
{
    int now=t;
    while(now!=s)
    {
        cap[id[now]]-=x,cap[id[now]^]+=x;
        now=pre[now];
    }
}
void il get_ans(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS(s,t))
    {
        //printf("%d\n",flow[t]);
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
il void adx(int x,int y,int cax,int c)
{
    add(x,y,cax,c),add(y,x,,-c);
}
int main()
{
    int n,sum=,s=,t=;
    scanf("%d",&n);
    for(int i=;i<=n;i++)
     scanf("%d",&val[i]),sum+=val[i];
    sum/=n;
    for(int i=;i<=n;i++)
    {
        val[i]-=sum;
        if(val[i]>) add(s,i,val[i],),add(i,s,,);
        else add(i+n,t,-val[i],),add(t,i+n,,);
    }
    for(int i=;i<=n;i++)
    {
        if(i!=n)
         adx(i,i+,inf,),adx(i,i+n+,inf,);
        if(i!=)
         adx(i,i-,inf,),adx(i,i+n-,inf,);
    }
    adx(,n,inf,),adx(,*n,inf,),adx(n,,inf,),adx(n,n+,inf,);
    get_ans(s,t);
    return printf("%d",min_cost)*;
}
           

4.魔术球问题

emmm

好题,真的是好题。

类型:最小路径覆盖

QWQ

我们把柱子看做路径,然后把球成点。

枚举球的数量,看看这些球的最小覆盖路径是多少。

是否大于柱子。

建图:每增加一个新节点,枚举前面的节点看看是否为平方数,是就建边。

实现:枚举!

按说应该二分的,但是若我们进行二分,就得重新建图。

那么多数组初始化,肯定很慢的。

若我们枚举,每次多加一个球,那我们就可以在原来的残留网络上跑最大流啦,快的一批。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath> 
#define il inline
using namespace std;
const int inf=;
const int maxm=+;
const int anx=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*];
int top[maxm];
int cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[*anx+],id[maxm],preflow=,anaa;
int ans[maxm];
queue <int> dl;
bool vis[maxm];
il int BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    pre[s]=,flow[s]=inf;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        if(x==t) break;
        for(int i=head[x];i;i=net[i])
        if(to[i]!=s&&cap[i]>&&pre[to[i]]==-)
        {
            pre[to[i]]=x,id[to[i]]=i;
            flow[to[i]]=min(flow[x],cap[i]);
            dl.push(to[i]);
        }
    }
    if(pre[t]==-) return -;
    else return flow[t];
}
il void change_cap(int s,int t,int x)
{
    int now=t,last,sum=;
    while(now!=s)
    {
        cap[id[now]]-=x;
        cap[id[now]^]+=x;
        now=pre[now];
    }
}
il void maxflow(int s,int t)
{
    //int max_flow=preflow;
    int d=;
    while((d=(BFS(s,t)))!=-)
    {
        change_cap(s,t,d);
        anaa-=d;
    }
    //return anaa;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
int main()
{
    freopen("balla.in","r",stdin);
    freopen("balla.out","w",stdout);
    int nowball=;
    int n,s,t;
    scanf("%d",&n);
    s=,t=;
    while()
    {
        anaa++;
        nowball++;
        for(int i=;i<nowball;i++)
         if(sqrt(i+nowball)==(int)sqrt(i+nowball)) adx(i,nowball+anx,);
        adx(s,nowball,),adx(nowball+anx,t,);
        maxflow(s,t);
        if(anaa>n) break;
    }
    printf("%d",--nowball);
    for(int i=;i<=nowball;i++)
     for(int j=head[i];j;j=net[j])
      if(cap[j]==) ans[i]=to[j]-anx;
    puts("");
    for(int i=;i<=nowball;i++)
    {
        if(vis[i]) continue;
        int now=i;
        while(now!=-anx) 
         printf("%d ",now),vis[now]=,now=ans[now];
        puts("");
    }
    return ;
}
           

5.餐巾

类型:最小费用最大流

建模分析:首先 将每天拆成两个点

X代表每天需要的毛巾

Y代表每天产生的旧毛巾

需要的毛巾

1.每天需要的毛巾可以直接来自于购买毛巾

因此从源点向X连一条容量为need,费用为购买费用的边

2.每天需要的毛巾可以来源于之前洗的旧毛巾

因此从d1天前和d2天前产生旧毛巾的点向本天需要的点连容量无限大,费用为清洗费用的点

3.从每天需要的点向汇点连一条容量为need,费用为0的边

旧毛巾

1.每天至少产生need条旧毛巾

因此从源点向本天旧毛巾点连一条容量为need,费用为0的点

2.上一天的旧毛巾可以不去清洗

因此从上一天的旧毛巾点向本天的旧毛巾点连一条容量为inf,费用为0的点

分析:因为其他边都为无穷边,所以我们最终跑出的最大流即为need之和,最小费用流为答案

CODE

题目传送门

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define il inline
#define ll long long
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],net[maxm*];
ll cost[maxm*],cap[maxm*];
int cnt=;
il void add(int x,int y,ll c,ll z){cnt++,to[cnt]=y,cost[cnt]=z,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
ll flow[maxm],dis[maxm],max_flow,min_cost;
int pre[maxm],id[maxm];
ll need[maxm];
bool vis[maxm];
queue <int> dl;
il bool BFS(ll s,ll t)
{
    while(!dl.empty()) dl.pop();
    for(int i=;i<=;i++) pre[i]=-,dis[i]=inf;
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]>dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
il void change_cap(int s,int t,ll x)
{
    int now=t;
    while(now!=s)
    {
        cap[id[now]]-=x,cap[id[now]^]+=x;
        now=pre[now];
    }
}
void il get_ans(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
il void adx(int x,int y,ll cax,ll c)
{
    add(x,y,cax,c),add(y,x,,-c);
}
il ll read()
{
    ll x=,w=;char ch=;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<)+(x<<)+ch-'0';ch=getchar();}
    return x*w; 
}
int main()
{
    freopen("napkin.in","r",stdin);
    freopen("napkin.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(int i=;i<=n;i++)
     need[i]=read();
    ll p=read(),d1=read(),p1=read(),d2=read(),p2=read();
    int s=,t=;
    for(int i=;i<=n;i++)
    {
        adx(s,i,need[i],p),adx(s,i+n,need[i],);//i为需求毛巾数量,第一个模拟的是直接购买毛巾的数量,第二个为今日旧毛巾的数量 
        adx(i,t,need[i],); 
        if(i+d1<=n) adx(i+n,i+d1,inf,p1);
        if(i+d2<=n) adx(i+n,i+d2,inf,p2);//今日需求毛巾可以由之前的快洗和慢洗毛巾得来
        if(i+<=n)  adx(i+n,i++n,inf,);
    }
    get_ans(s,t);
    return printf("%lld\n",min_cost)*;
}
           

6.最小路径覆盖问题

问题:给你若干个点和边,问最少用几条路可以覆盖掉全图。

问题转化:网络流

题目传送门

分析:

我们首先将原图用n条路径覆盖,每条边只经过每个节点。

现在尽量合并更多的路径(即将两个路径通过一条边首尾相连)。

可以知道,每合并两条路径,图中的路径覆盖数就会减少1。

所以我们只需要利用网络流合并相关的路径即可。

答案求解:

首先将每个节点拆成(Xi,Yi)两个节点,建立源点和汇点,分别连接(S,Xi)和(Yi,T)。

然后对于每一条原图中的边,建立边(Xi,Yi)即可。

这样每一条增广路都只会经过2个节点(Xa,Yb),对应合并的两个节点。

由于每个节点至多与一个节点合并,故边(S,Xi)和(Yi,T)容量为1。

此时的最大流对应的就是最多可以合并的路径数。

至于输出路径嘛,这题是SPJ,瞎搞就行。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath> 
#define il inline
using namespace std;
const int inf=;
const int maxm=+;
const int anx=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*];
int top[maxm];
int cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[],id[maxm],preflow=,anaa;
int ans[maxm];
queue <int> dl;
bool vis[maxm];
il int BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    pre[s]=,flow[s]=inf;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        if(x==t) break;
        for(int i=head[x];i;i=net[i])
        if(to[i]!=s&&cap[i]>&&pre[to[i]]==-)
        {
            pre[to[i]]=x,id[to[i]]=i;
            flow[to[i]]=min(flow[x],cap[i]);
            dl.push(to[i]);
        }
    }
    if(pre[t]==-) return -;
    else return flow[t];
}
il void change_cap(int s,int t,int x)
{
    int now=t,last,sum=;
    while(now!=s)
    {
        cap[id[now]]-=x;
        cap[id[now]^]+=x;
        now=pre[now];
    }
}
il int maxflow(int s,int t)
{
    int max_flow=;
    int d=;
    while((d=(BFS(s,t)))!=-)
    {
        change_cap(s,t,d);
        max_flow+=d;
    }
    return max_flow;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
int main()
{
    int n,m,s=,t;
    scanf("%d%d",&n,&m);
    t=;
    for(int i=;i<=n;i++) adx(s,i,),adx(i+anx,t,); 
    for(int i=;i<=m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        adx(a,b+anx,);
    }
    int Ans=maxflow(s,t);
    for(int i=;i<=n;i++)
     for(int j=head[i];j;j=net[j])
      if(cap[j]==) ans[i]=to[j]-anx;
    for(int i=;i<=n;i++)
    {
        if(vis[i]) continue;
        int now=i;
        while(now!=-anx) 
         printf("%d ",now),vis[now]=,now=ans[now];
        puts("");
    }
    return printf("%d\n",n-Ans)*;
}
           

7.试题库问题

这道题基本上算是网络流最简单的题了。

首先建图(屁话

首先,对于每个题库可以向汇点连一条容量为需求的边。

对于每个题目,先从源点向每个题目连一条容量为1的边。

然后从每个题目向所属题库连容量为1的边。

然后,没了。。。

方案输出,找一下cap为0的就行了。

SPJ的评测

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath> 
#include <vector>
#define il inline
using namespace std;
const int inf=;
const int maxm=+;
const int anx=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*];
int top[maxm];
int cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[],id[maxm],preflow=,anaa;
queue <int> dl;
bool vis[maxm];
vector <int> ans[];
il int BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    pre[s]=,flow[s]=inf;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        if(x==t) break;
        for(int i=head[x];i;i=net[i])
        if(to[i]!=s&&cap[i]>&&pre[to[i]]==-)
        {
            pre[to[i]]=x,id[to[i]]=i;
            flow[to[i]]=min(flow[x],cap[i]);
            dl.push(to[i]);
        }
    }
    if(pre[t]==-) return -;
    else return flow[t];
}
il void change_cap(int s,int t,int x)
{
    int now=t,last,sum=;
    while(now!=s)
    {
        cap[id[now]]-=x;
        cap[id[now]^]+=x;
        now=pre[now];
    }
}
il int maxflow(int s,int t)
{
    int max_flow=;
    int d=;
    while((d=(BFS(s,t)))!=-)
    {
        change_cap(s,t,d);
        max_flow+=d;
    }
    return max_flow;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
int main()
{
    int n,k;
    scanf("%d%d",&k,&n);
    int s=,t=;
    for(int i=,x;i<=k;i++)
     scanf("%d",&x),adx(i,t,x);
    for(int i=;i<=n;i++)
    {
        int p;
        adx(s,i+n,);
        scanf("%d",&p);
        for(int j=,x;j<=p;j++)
         scanf("%d",&x),adx(i+n,x,);
    }
    maxflow(s,t);
    //printf("This is ans\n");
    for(int i=;i<=n;i++)
    {
        for(int j=head[i+n];j;j=net[j])
         if(cap[j]==)
         {
            ans[to[j]].push_back(i);
            break;
         }
    } 
    for(int i=;i<=k;i++)
    {
        printf("%d:",i);
        for(int j=;j<ans[i].size();j++)
         printf(" %d",ans[i][j]);
        puts("");
    }
    return ;
}
           

8.星际转移问题

类型:网络最大流

分析:

飞船对于不同的时间,航道不同,所以用时间建模。

不停的增加时间,用飞船运载乘客,当某一时刻图中的最大流超过了乘客数,即为最小的花费时间。

建模:

首先从源点向地球连一条inf的边

从月球向汇点连一条inf的边

由于乘客可以在空间站等待,所以从上个时刻空间站的点(包括地月)向本时刻连一条inf的边

从飞船的上一时刻位置向本时刻位置连一条p[i]的边

然后不停跑最大流就可以了。

问题 :不存在的情况,即无从地球通往月球的航道,并查集即可解决。

懒得搞了,天数>600时输出无解。。。

CODE

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <cmath> 
#include <vector>
#define il inline
using namespace std;
const int inf=;
const int maxm=+;
const int anx=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*];
int p[maxm];
int cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[],id[maxm],preflow=,anaa;
queue <int> dl;
bool vis[maxm];
int dx[][],len[],n,m,k;;
il int BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    pre[s]=,flow[s]=inf;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        if(x==t) break;
        for(int i=head[x];i;i=net[i])
        if(to[i]!=s&&cap[i]>&&pre[to[i]]==-)
        {
            pre[to[i]]=x,id[to[i]]=i;
            flow[to[i]]=min(flow[x],cap[i]);
            dl.push(to[i]);
        }
    }
    if(pre[t]==-) return -;
    else return flow[t];
}
il void change_cap(int s,int t,int x)
{
    int now=t,last,sum=;
    while(now!=s)
    {
        cap[id[now]]-=x;
        cap[id[now]^]+=x;
        now=pre[now];
    }
}
il int maxflow(int s,int t)
{
    int max_flow=preflow;
    int d=;
    while((d=(BFS(s,t)))!=-)
    {
        change_cap(s,t,d);
        max_flow+=d;
    }
    return max_flow;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
void make_map(int day)
{
    for(int i=;i<=n;i++)
    adx(i+(day-)*n,i+day*n,inf);
    for(int i=;i<=m;i++)
    {
     int x=dx[i][(day-)%len[i]];
     int y=dx[i][day%len[i]];
     adx((day-)*n+x,day*n+y,p[i]);
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    n+=;
    for(int i=,size;i<=m;i++)
    {
        scanf("%d",&p[i]);
        scanf("%d",&size);
        len[i]=size;
        for(int j=;j<size;j++)
         {
            scanf("%d",&dx[i][j]);
            dx[i][j]+=;
         }   
    }
    int s=,t=;
    int day=;
    while()
    {
        adx(s,day*n+,inf),adx(day*n+,t,inf);
        if(day>=)
         make_map(day); 
        preflow=maxflow(s,t);
        if(preflow>=k) 
        {
            printf("%d\n",day);
            return ;
        }
        day++;
        if(day==)
        {
            printf("0\n");
            return ;
        }
    }
}
           

9.运输问题

这题也太裸了。。。。

类型:费用流

建图:

从源点向仓库连容量为提供量,费用为0的边

从商店向汇点连容量为需求量,费用为0的边

从每个仓库向商店连容量inf,费用为运输费的边

第一问跑最小费用最大流

第二问跑最大费用最大流

啥,你问我咋跑最大费用,SPFA跑最长路就行啊(滑稽

题目链接

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*],cost[maxm*];
int need[maxm],sup[maxm],wt[][];
int cnt=;
il void add(int x,int y,int c,int z){cnt++,to[cnt]=y,cost[cnt]=z,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[maxm],id[maxm],dis[maxm],max_flow,min_cost;
bool vis[maxm];
queue <int> dl;
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,/,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]>dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
il void change_cap(int s,int t,int x)
{
    int now=t;
    while(now!=s)
    {
        cap[id[now]]-=x,cap[id[now]^]+=x;
        now=pre[now];
    }
}
il bool BFS1(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]<dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
void il get_ans(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
void il get_ans1(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS1(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
il void adx(int x,int y,int cax,int c)
{
    add(x,y,cax,c),add(y,x,,-c);
}
int main()
{
    freopen("tran.in","r",stdin);
    freopen("tran.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    int s=,t=m+n+;
    for(int i=;i<=n;i++)
     scanf("%d",&sup[i]),adx(s,i,sup[i],);
    for(int i=;i<=m;i++)
     scanf("%d",&need[i]),adx(i+n,t,need[i],);
    for(int i=;i<=n;i++)
     for(int j=,x;j<=m;j++)
      scanf("%d",&wt[i][j]),adx(i,j+n,inf,wt[i][j]);
    get_ans(s,t);
    printf("%d\n",min_cost);
    memset(head,,sizeof(head)),memset(to,,sizeof(to));
    memset(cap,,sizeof(cap)),memset(cost,,sizeof(cost));
    cnt=;
    for(int i=;i<=n;i++)
     adx(s,i,sup[i],);
    for(int i=;i<=m;i++)
     adx(i+n,t,need[i],);
    for(int i=;i<=n;i++)
     for(int j=,x;j<=m;j++)
      adx(i,j+n,inf,wt[i][j]);
    get_ans1(s,t);
    return printf("%d\n",min_cost)*;
}
           

10.航空问题

费用流问题。

建图:

源点向起点连inf费用为0的边

终点向汇点连inf费用为0的边

除了起点终点,每个点只能走一次。

所以拆点,容量为1,费用为1

起点终点容量为2,费用为1

输入的边容量为1费用为0

跑最大费用流

若最大流为2,则有解

因为起点终点经过两次 所以 答案-2

CODE

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*],cost[maxm*];
map <string,int> idx;
string name[maxm];
int cnt=;
il void add(int x,int y,int c,int z){cnt++,to[cnt]=y,cost[cnt]=z,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[maxm],id[maxm],dis[maxm],max_flow,min_cost,ans[maxm],w[maxm];
bool vis[maxm];
queue <int> dl;
il void change_cap(int s,int t,int x)
{
    int now=t;
    while(now!=s)
    {
        cap[id[now]]-=x,cap[id[now]^]+=x;
        now=pre[now];
    }
}
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]<dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
void il get_ans(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
il void adx(int x,int y,int cax,int c)
{
    add(x,y,cax,c),add(y,x,,-c);
}
int main()
{
     int n,v;
     scanf("%d%d",&n,&v);
     int s=,t=;
     for(int i=;i<=n;i++)
     {
        cin>>name[i];
        idx[name[i]]=i;
        if(i!=&&i!=n) adx(i,i+n,,);
        else adx(i,i+n,,);
        w[i]=cnt;
     }
    adx(s,,inf,);
    adx(*n,t,inf,);
    for(int i=;i<=v;i++)
    {
        string s1,s2;
        cin>>s1>>s2;
        adx(idx[s1]+n,idx[s2],,);
    } 
    get_ans(s,t);
    if(max_flow!=) printf("No Solution!\n");
    else
    {
        memset(vis,,sizeof(vis)); 
        printf("%d\n",min_cost-);
    }
}
           

10.分配问题

类型:最小费用流

这题是裸题

qwq

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*],cost[maxm*];
int need[maxm],sup[maxm],wt[][];
int cnt=;
il void add(int x,int y,int c,int z){cnt++,to[cnt]=y,cost[cnt]=z,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
int flow[maxm],pre[maxm],id[maxm],dis[maxm],max_flow,min_cost;
bool vis[maxm];
queue <int> dl;
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,/,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]>dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
il void change_cap(int s,int t,int x)
{
    int now=t;
    while(now!=s)
    {
        cap[id[now]]-=x,cap[id[now]^]+=x;
        now=pre[now];
    }
}
il bool BFS1(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(pre,-,sizeof(pre));
    memset(dis,,sizeof(dis));
    dis[s]=,flow[s]=inf,pre[s]=,vis[s]=;
    dl.push(s);
    while(!dl.empty())
    {
        int x=dl.front();
        dl.pop();
        vis[x]=;
        for(int i=head[x];i;i=net[i])
        {
           int tmp=to[i];
           if(cap[i]>&&dis[tmp]<dis[x]+cost[i])
           {
              dis[tmp]=dis[x]+cost[i];
              pre[tmp]=x;
              id[tmp]=i;
              flow[tmp]=min(flow[x],cap[i]);
              if(!vis[tmp]) vis[tmp]=,dl.push(tmp);
           }
        }
    }
    return pre[t]==-?:;
}
void il get_ans(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
void il get_ans1(int s,int t)
{
    max_flow=,min_cost=;
    while(BFS1(s,t))
    {
        max_flow+=flow[t],min_cost+=dis[t]*flow[t];
        change_cap(s,t,flow[t]);
    }
}
il void adx(int x,int y,int cax,int c)
{
    add(x,y,cax,c),add(y,x,,-c);
}
int main()
{
    int n;
    scanf("%d",&n);
    int s=,t=;
    for(int i=;i<=n;i++)
    {
        adx(s,i,,);
        adx(i+n,t,,);
        for(int j=;j<=n;j++)
         scanf("%d",&wt[i][j]),adx(i,j+n,,wt[i][j]);
    }
    get_ans(s,t);
    printf("%d\n",min_cost);
    memset(head,,sizeof(head)),memset(to,,sizeof(to));
    memset(cap,,sizeof(cap)),memset(cost,,sizeof(cost));
    cnt=;
    for(int i=;i<=n;i++)
    {
        adx(s,i,,);
        adx(i+n,t,,);
        for(int j=;j<=n;j++)
         adx(i,j+n,,wt[i][j]);
    }
    get_ans1(s,t);
    printf("%d\n",min_cost);
    return ;
}
           

11.圆桌问题

类型:网络最大流

建模:

对于每组人员,从源点S向每组连一条容量为人员数量的边

对于每个桌子,向汇点T连一条容量为容纳人员数量的边

每组人员向每个桌子连一条容量为1的边即可。

Judge:跑出来的最大流是否等于总人数

方案:枚举即可

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring> 
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[maxm],to[maxm*],cap[maxm*],net[maxm*],deep[maxm],cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
queue <int> dl;
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(deep,-,sizeof(deep));
    dl.push(s),deep[s]=;
    while(!dl.empty())
    {
        int x=dl.front();dl.pop();
        for(int i=head[x];i;i=net[i])
         if(cap[i]>&&deep[to[i]]==-)
          dl.push(to[i]),deep[to[i]]=deep[x]+;
    }
    return deep[t]==-?:;
}
int dfs(int now,int flow,int t)
{
    if(now==t) return flow;
    int w,used=;
    for(int i=head[now];i;i=net[i])
    {
        int v=to[i];
        if(deep[v]==deep[now]+&&cap[i])
        {
            w=dfs(v,min(flow-used,cap[i]),t);
            cap[i]-=w;
            cap[i^]+=w;
            used+=w;
            if(used==flow) return flow;
        }
    }
    if(!used) deep[now]=-;
    return used;
}
il int dinic(int s,int t)
{
    int maxflow=;
    while(BFS(s,t)) maxflow+=dfs(s,inf,t);
    return maxflow;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
il int read()
{
    int x=,w=;
    char ch=;
    while(ch<'0'||ch>'9') 
    {
        if(ch=='-') w=-;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
     x=(x<<)+(x<<)+ch-'0',ch=getchar();
    return x*w;
}
int main()
{
    //freopen("roundtable.in","r",stdin);
    //freopen("roundtable.out","w",stdout);
    int n,m;
    n=read(),m=read();
    int s=,t=,sum=;
    for(int i=,x;i<=n;i++)
    {
        x=read(),sum+=x;
        adx(s,i,x);
    }
    for(int i=,x;i<=m;i++)
    {
        x=read();
        adx(i+n,t,x);   
    }
    for(int i=;i<=n;i++)
     for(int j=;j<=m;j++)
      adx(i,j+n,);
    int ans=(dinic(s,t)==sum);
    printf("%d\n",ans);
    if(ans)
    {
        for(int i=;i<=n;i++)
        {
          for(int j=head[i];j;j=net[j])
           if(cap[j]==) printf("%d ",to[j]-n);
          puts("");
        }
    }
    return ;
}
           

12.最长不下降子序列问题

qwq

类型:最大不交叉路径->最大流

第一问 可以用 n^2的办法解决,同时求出以某个数字最作为结尾时最长的不下降最序列长度,len[i]。

第二问 题目要求每个数字只用一次,问题为最大不交叉路径

考虑通过第一问求出的数组来分层建图

首先每个数字只用一次,很明显要拆点

当一个位置的len[i]为第一问答案时,这个位置可以作为结尾,于是从源点连一条容量为inf的边

反之,当一个位置len[i]=1时,那么这个位置可以作为开头,于是从此点的出点向汇点连一条inf的边

对于 i<j并且val[i]<=val[j]len[i]==len[j]−1时 i < j 并 且 v a l [ i ] <= v a l [ j ] l e n [ i ] == l e n [ j ] − 1 时 ,这两个点可以接在一起,于是从j的出点向i的入点建一条容量为1的边

跑最大流即为答案

第三问,将1和n的出点和入点的边容量改为inf即可

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring> 
#define il inline
using namespace std;
const int inf=;
const int maxm=;
int head[],to[maxm*],cap[maxm*],net[maxm*],deep[],cnt=;
il void add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;}
queue <int> dl;
int maxlen[maxm],val[maxm];
il bool BFS(int s,int t)
{
    while(!dl.empty()) dl.pop();
    memset(deep,-,sizeof(deep));
    dl.push(s),deep[s]=;
    while(!dl.empty())
    {
        int x=dl.front();dl.pop();
        for(int i=head[x];i;i=net[i])
         if(cap[i]>&&deep[to[i]]==-)
          dl.push(to[i]),deep[to[i]]=deep[x]+;
    }
    return deep[t]==-?:;
}
int dfs(int now,int flow,int t)
{
    if(now==t) return flow;
    int w,used=;
    for(int i=head[now];i;i=net[i])
    {
        int v=to[i];
        if(deep[v]==deep[now]+&&cap[i])
        {
            w=dfs(v,min(flow-used,cap[i]),t);
            cap[i]-=w;
            cap[i^]+=w;
            used+=w;
            if(used==flow) return flow;
        }
    }
    if(!used) deep[now]=-;
    return used;
}
il int dinic(int s,int t)
{
    int maxflow=;
    while(BFS(s,t)) maxflow+=dfs(s,inf,t);
    return maxflow;
}
inline void adx(int x,int y,int cax)
{
    add(x,y,cax),add(y,x,);
}
il int read()
{
    int x=,w=;
    char ch=;
    while(ch<'0'||ch>'9') 
    {
        if(ch=='-') w=-;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
     x=(x<<)+(x<<)+ch-'0',ch=getchar();
    return x*w;
}
int main()
{
    freopen("alis.in","r",stdin);
    freopen("alis.out","w",stdout);
    int n=read();
    for(int i=;i<=n;i++)
     val[i]=read();
    for(int i=;i<=n;i++)
     maxlen[i]=;
    int ans=;
    for(int i=;i<=n;i++)
     for(int j=;j<i;j++)
      if(val[j]<=val[i]) maxlen[i]=max(maxlen[i],maxlen[j]+),ans=max(ans,maxlen[i]);
    printf("%d\n",ans);
    if(ans==) printf("%d\n%d\n",n,n);
    if(ans==) printf("0\n0\n");
    if(ans!=&&ans!=)
    {
         int s=,t=;
         for(int i=;i<=n;i++)
         {
            adx(i,i+n,);
            if(maxlen[i]==ans) adx(s,i,inf);
            if(maxlen[i]==) adx(i+n,t,inf);
            for(int j=;j<i;j++)
             if(val[j]<=val[i]&&maxlen[j]+==maxlen[i]) adx(i+n,j,);
         }
         printf("%d\n",dinic(s,t));
         memset(head,,sizeof(head)),cnt=;
         for(int i=;i<=n;i++)
         {
            if(i!=&&i!=n) adx(i,i+n,);
            else adx(i,i+n,inf);
            if(maxlen[i]==ans) adx(s,i,inf);
            if(maxlen[i]==) adx(i+n,t,inf);
            for(int j=;j<i;j++)
             if(val[j]<=val[i]&&maxlen[j]+==maxlen[i]) adx(i+n,j,);
         } 
         printf("%d\n",dinic(s,t));
    }
    return ;
}
           

13.孤岛营救问题

类型:状压+BFS

不是网络流(滑稽

很明显是个状压嘛。

我们状态压缩钥匙。

vis[x][y][S] v i s [ x ] [ y ] [ S ] 表示在x y这个位置持有钥匙状态为S是否来过

BFS队列里存4个变量

分别为当前横纵坐标,步数以及钥匙状态

map[x1][y1][x2][y2]表示两个点直接是否有墙或者是门。

pas[x][y][i]表示x y这个点放的钥匙的种类

num[x][y]表示当前点钥匙数目

坑点:

1.钥匙不是用了就没了((#`O′)喂,没了才有问题吧

2.一个点可以放多个钥匙(人家又没说只放一个。

3.初始点可以放钥匙

4.别忘了输出-1….

虽然我只被2坑了

CODE

题目传送门

#include <cstdio>
#include <iostream>
#include <queue> 
#define il inline 
using namespace std;
bool vis[][][(<<)];
int map[][][][];
int pas[][][],num[][];
struct node{
    int x,y,step,cos;
}; 
queue <node> dl;
int n,m,p,k;
int dx[]={,,-,,},dy[]={,,,,-};
il int BFS()
{
    int nows=;
    for(int i=;i<=num[][];i++)
     nows|=(<<(pas[][][i]-));
    vis[][][nows]=;
    dl.push((node){,,,nows});
    while(!dl.empty())
    {
        node now=dl.front();
        dl.pop();
        if(now.x==n&&now.y==m)
         return now.step; 
        for(int i=;i<=;i++) 
         {
           int xx=now.x+dx[i],yy=now.y+dy[i],t;
           if(xx<||yy<||xx>n||yy>m) continue;
           if(map[now.x][now.y][xx][yy]==-) continue;
           if((t=map[now.x][now.y][xx][yy])!=)
            if((now.cos&(<<(t-)))==) continue;
           int cosx=now.cos;
           for(int j=;j<=num[xx][yy];j++)
            cosx|=(<<(pas[xx][yy][j]-));
           if(vis[xx][yy][cosx]) continue;
           vis[xx][yy][cosx]=;
           dl.push((node){xx,yy,now.step+,cosx});
         }
    }
    return -;
}
int main()
{
    //freopen("rescue.in","r",stdin);
    //freopen("rescue.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&p,&k);
    for(int i=;i<=k;i++)
    {
        int x1,x2,y1,y2,g;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&g);
        if(g==) map[x1][y1][x2][y2]=map[x2][y2][x1][y1]=-;
        else map[x1][y1][x2][y2]=map[x2][y2][x1][y1]=g;
    }
    int s;
    scanf("%d",&s);
    for(int i=;i<=s;i++)
    {
        int x,y,p;
        scanf("%d%d%d",&x,&y,&p);
        pas[x][y][++num[x][y]]=p;
    }
    printf("%d\n",BFS());
    return ;
} 
           

14.汽车行驶问题

按照要求BFS就行了,

坑点:强制消费。

qwq

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define il inline
using namespace std;
int vis[][][],n,a,b,c,k;
struct node{
    int x,y,cost,oil;
};
queue <node> dl;
bool map[][];
int dx[]={,,-,,},dy[]={,,,,-};
il int BFS()
{
    memset(vis,/,sizeof(vis));
    dl.push((node){,,,k});
    vis[][][k]=;
    while(!dl.empty())
    {
        node now=dl.front();
        //printf("%d %d %d %d\n",now.x,now.y,now.cost,now.oil);
        node nex;
        dl.pop();
        if(now.oil==) continue;
        //printf("1\n");
        for(int i=;i<=;i++)
        {
            int xx=now.x+dx[i],yy=now.y+dy[i];
            if(xx<||yy<||xx>n||yy>n) continue;
            nex.x=xx,nex.y=yy,nex.cost=now.cost,nex.oil=now.oil-;
            if(nex.x<now.x||nex.y<now.y) nex.cost+=b;
            if(map[nex.x][nex.y]) 
             nex.oil=k,nex.cost+=a;
            if(vis[nex.x][nex.y][nex.oil]>nex.cost) vis[nex.x][nex.y][nex.oil]=nex.cost,dl.push(nex);
            if(map[nex.x][nex.y]==)
             {
                nex.oil=k,nex.cost+=(a+c);
                if(vis[nex.x][nex.y][nex.oil]>nex.cost) vis[nex.x][nex.y][nex.oil]=nex.cost,dl.push(nex);
             }
        }
    }
    int ans=vis[][][];
    for(int i=;i<=k;i++) 
     ans=min(ans,vis[n][n][i]);
    return ans;
}
int main()
{
    scanf("%d%d%d%d%d",&n,&k,&a,&b,&c);
    for(int i=;i<=n;i++)
     for(int j=;j<=n;j++)
      scanf("%d",&map[i][j]);
    return printf("%d\n",BFS())*;
}
           

15.太空飞行计划问题

http://blog.csdn.net/qq_35914587/article/details/79155879

忘了有这个分类了,写完了才想起来,不粘贴了。

16.方格取数问题

http://blog.csdn.net/qq_35914587/article/details/79163024

17.骑士共存问题

http://blog.csdn.net/qq_35914587/article/details/79163404