一些网络流。

POJ 3281

 题意:每一头牛都有它喜欢吃的食物和饮料,问最多能满足多少头牛 让它吃到它喜欢吃的食物和饮料。


  思路:从源点S对每一个食物连一条边,容量为1, 然后食物对喜欢吃这种食物的牛连边,容量也为1,然后每头牛连一条边到喜欢吃的饮料 容量也为1。

     每个饮料连边到汇点,容量为1。  这样图构好了,但是每头牛可能会产生吃多个食物或者多个饮料的情况,所以对牛这个点也要进行限制。每头牛限制通过的流量为1

   把牛拆成两个点 中间连一条容量为1的边,每个点分别连着食物和饮料,这样求一个最大流就行了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#define INF 100000000
using namespace std;
struct edge{
   int to;
   int cap;
   int rav;
};
vector<edge> G[808];
int level[808];
int iter[808];
int n,f,d;
void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s)
{
    queue<int> q;
    memset(level,-1,sizeof(level));
    level[s]=0;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();i++)
        {
            edge &e=G[u][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[u]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v];i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rav].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)
{
    int flow=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0) return flow;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)
            flow+=f;
    }
}
int main()
{
      while(scanf("%d%d%d",&n,&f,&d)!=EOF)
      {
          for(int i=0;i<=(n+n+f+d);i++)
             G[i].clear();
          for(int i=1;i<=f;i++)
            add_edge(0,i,1);
          for(int i=1;i<=n;i++)
          {
              int f1,d1;
              scanf("%d%d",&f1,&d1);
              for(int j=0;j<f1;j++)
              {
                  int p;
                  scanf("%d",&p);
                  add_edge(p,i+f,1);
              }
              add_edge(i+f,i+n+f,1);
              for(int j=0;j<d1;j++)
              {
                  int p;
                  scanf("%d",&p);
                  add_edge(i+n+f,p+n+n+f,1);
              }
          }
          for(int i=1;i<=d;i++)
            add_edge(i+n+n+f,n+n+f+d+1,1);
            int ans;
              int k=2*n+f+d+1;
              ans=max_flow(0,k);
          printf("%d\n",ans);
      }
}



POJ  2135

  题意:一个农夫从1号农田到N号农田 走一个来回 要求不走相同的路且最短。

 思路:建立最小费用流模型,距离为消费,容量为1,然后求1-N流量为2的最小费用就行了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iostream>
#define INF 1000000000
using namespace std;
struct edge
{
    int to;
    int cap;
    int cost;
    int rav;
};
vector<edge> G[1005];
int dist[1005];
int n;
int prevv[1005];
int preve[1005];
bool inque[1005];
void add_edge(int from,int to,int cap,int cost)
{
    G[from].push_back((edge){to,cap,cost,G[to].size()});
    G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
int min_liu(int s,int t,int f)
{
    int res=0;
    while(f>0)
    {
        fill(dist,dist+n,INF);
        memset(inque,0,sizeof(inque));
        dist[s]=0;
        queue<int> q;
        inque[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            inque[u]=0;
            for(int i=0;i<G[u].size();i++)
            {
                edge &e=G[u][i];
                //cout<<u<<" "<<e.to<<" "<<e.cap<<" "<<e.cost<<" "<<dist[e.to]<<" "<<dist[u]+e.cost<<endl;
                if(e.cap>0&&dist[e.to]>dist[u]+e.cost)
                {
                    dist[e.to]=dist[u]+e.cost;
                    prevv[e.to]=u;
                    preve[e.to]=i;
                    if(!inque[e.to])
                    {
                        inque[e.to]=1;
                        q.push(e.to);
                    }
                }
            }
        }
        //cout<<endl;
        if(dist[t]==INF) return -1;
        res+=dist[t];
        for(int v=t;v!=s;v=prevv[v])
        {
            edge &e=G[prevv[v]][preve[v]];
            //cout<<prevv[v]<<endl;
            e.cap--;
            G[v][e.rav].cap++;
            //cout<<v<<" "<<G[v][e.rav].to<<endl;
        }
        f--;
    }
    return res;
}
int main()
{
    int m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=0;i<n;i++)
            G[i].clear();
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            add_edge(a-1,b-1,1,c);
            add_edge(b-1,a-1,1,c);
        }
        printf("%d\n",min_liu(0,n-1,2));
    }

POJ 3686

题意:有一些玩具和一些工厂  每个玩具在不同的工厂加工的时间不同,问平均时间最短多少。

思路:对于一个工厂 如果有k个玩具加工 总时间为T=k*a1+(k-1)*a2+......1*ak;

     我们可以把每个工厂的点拆成N个,每个玩具对第i个工厂的第j个点连边 费用为 j*Zx.表示这个玩具在这个工厂第j个加工。

    然后求一个最小费用就行了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#define INF 1000000000
using namespace std;
struct edge{
     int to;
     int cap;
     int cost;
     int rav;
};
vector<edge> G[3005];
void add_edge(int from,int to,int cap,int cost)
{
    G[from].push_back((edge){to,cap,cost,G[to].size()});
    G[to].push_back((edge){from,0,-cost,G[from].size()-1});
}
int dist[3005];
bool inque[3005];
int prevv[3005];
int preve[3005];
int min_liu(int s,int t,int f)
{
    int res=0;
    while(f>0)
    {
        queue<int> q;
        fill(dist,dist+t+1,INF);
        dist[s]=0;
        q.push(s);
        inque[s]=1;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            inque[u]=0;
            for(int i=0;i<G[u].size();i++)
            {
                edge &e=G[u][i];
                if(e.cap>0&&dist[e.to]>dist[u]+e.cost)
                {
                    dist[e.to]=dist[u]+e.cost;
                    prevv[e.to]=u;
                    preve[e.to]=i;
                    if(!inque[e.to])
                    {
                        inque[e.to]=1;
                        q.push(e.to);
                    }
                }
            }
        }
        if(dist[t]==INF) return -1;
        int d=INF;
        for(int v=t;v!=s;v=prevv[v])
           d=min(d,G[prevv[v]][preve[v]].cap);
        f-=d;
        res+=d*dist[t];
        for(int v=t;v!=s;v=prevv[v])
        {
            edge &e=G[prevv[v]][preve[v]];
            e.cap-=d;
            G[v][e.rav].cap+=d;
        }
    }
    return res;
}
int k[105][105];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        //printf("\n");
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n*m+n+2;i++)
            G[i].clear();
        for(int i=1;i<=n;i++)
            add_edge(0,i,1,0);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
            scanf("%d",&k[i][j]);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                for(int k1=1;k1<=n;k1++)
                {
                    add_edge(i+1,n+k1+j*n,1,k1*k[i][j]);
                }
            }
        }
        for(int i=n+1;i<=(m+1)*n;i++)
            add_edge(i,(m+1)*n+1,1,0);
        double k=min_liu(0,(m+1)*n+1,n);

        printf("%.6f\n",k/(double)n);
    }
}

POJ 1698

题意: 有一些电影要拍,每个电影只能在特定的星期开拍,并且需要在多少个星期内拍完,问能否拍完。

思路: 每个电影对 他能拍的那一天连边 容量为1。 源点对电影连边 容量为电影需要拍的次数。然后每一天对汇点连边,容量为1,判断最大流是否为电影拍的总和即可。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<math.h>
#include<deque>
#define INF 1000000000
using namespace std;
struct edge{
    int to;
    int cap;
    int rav;
};
vector<edge> G[505];
int level[505];
int iter[505];
void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s)
{
    queue<int> q;
    q.push(s);
    memset(level,-1,sizeof(level));
    level[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();i++)
        {
            edge &e=G[u][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[u]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int v,int t,int f)
{
    if(v==t) return f;
    for(int &i=iter[v];i<G[v].size();i++)
    {
        edge &e=G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rav].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)
{
    int res=0;
    while(1)
    {
        bfs(s);
        if(level[t]==-1) return res;
        memset(iter,0,sizeof(iter));
        int f;
        while((f=dfs(s,t,INF))>0)
            res+=f;
    }
    return res;
}
bool vis[25][10];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        int n;
        scanf("%d",&n);
        for(int i=0;i<500;i++)
            G[i].clear();
        int l=n+1;
        int ma=0;
        int sum=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<7;j++)
                scanf("%d",&vis[i][j]);
            int f;
            scanf("%d",&f);
            add_edge(0,i+1,f);
            sum+=f;
            int w;
            scanf("%d",&w);
            for(int j=0;j<w;j++)
            {
                for(int k=0;k<7;k++)
                {
                    int s=j*7+k;
                    ma=max(ma,s);
                    if(vis[i][k])
                        add_edge(i+1,l+s,1);
                }
            }
        }
        for(int i=l;i<=ma+l;i++)
            add_edge(i,500,1);
        if(max_flow(0,500)==sum)
            printf("Yes\n");
        else printf("No\n");
    }
}

POJ 2112

题意: 有K个挤奶机和C头牛,每头挤奶机最多只能支持M头牛挤奶,求使得所走路程最远的奶牛路程最短的方案。

思路:先用floyd求点与点之间最短路,源点对每台挤奶机连一条容量为M的边,然后二分路程长度,每次把长度小于等于该长度的边连起来,然后用最大流判断是否可行。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#include<math.h>
#define INF 100000000
using namespace std;
struct edge{
    int to;
    int cap;
    int rav;
};
vector<edge> G[305];
int level[305];
int iter[305];
void add_edge(int from,int to,int cap)
{
    G[from].push_back((edge){to,cap,G[to].size()});
    G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    queue<int> q;
    q.push(s);
    level[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=0;i<G[u].size();i++)
        {
            edge &e=G[u][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to]=level[u]+1;
                q.push(e.to);
            }
        }
    }
}
int dfs(int u,int t,int f)
{
    if(u==t) return f;
    for(int &i=iter[u];i<G[u].size();i++)
    {
        edge &e=G[u][i];
        if(e.cap>0&&level[e.to]>level[u])
        {
            int d=dfs(e.to,t,min(f,e.cap));
            if(d>0)
            {
                e.cap-=d;
                G[e.to][e.rav].cap+=d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s,int t)
{
    int res=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0) return res;
        int f;
        memset(iter,0,sizeof(iter));
        while((f=dfs(s,t,INF))>0)
          res+=f;
    }
}
int k[305][305];
void floyd(int n)
{
    for(int k1=0;k1<n;k1++)
        for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
       {
           k[i][j]=min(k[i][j],k[i][k1]+k[k1][j]);

       }
}
void CLEAR(int l,int r)
{
    for(int i=l;i<=r;i++)
        G[i].clear();
}
int main()
{
    int K,N,M;
    while(scanf("%d%d%d",&K,&N,&M)!=EOF)
    {
        CLEAR(0,K+N+1);
        int n=K+N;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
        {
            scanf("%d",&k[i][j]);
            if(i!=j&&!k[i][j])
                k[i][j]=INF;
        }
        floyd(n);
        int l=0,r=20000;
        int now;
        while(1)
        {
            CLEAR(0,K+N+1);
            for(int i=1;i<=K;i++)
            add_edge(0,i,M);
            for(int i=K+1;i<=n;i++)
            add_edge(i,K+N+1,1);
            now=(l+r)>>1;
            for(int i=0;i<K;i++)
                for(int j=K;j<n;j++)
            {
                if(k[i][j]<=now)
                 add_edge(i+1,j+1,1);
            }
            int f=max_flow(0,n+1);
            //cout<<f<<" "<<now<<endl;
            if(f==N)
            {
                r=now;
            }
            else l=now+1;
            if(l>=r) break;
        }
        printf("%d\n",r);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值