kuangbin网络流题目POJ3436,一波小专题

1、POJ 3436

题意是真的迷,开始很难理解。

就是给一堆工厂,每个工厂加工的零件方法不同,工厂可以把如010加工成111,每个工厂有其的加工速度,问如何加工可以使得加工的数量,加工完全就是111的结果。

就网络流裸题,建立一个s连接到全部000的点,然后每个点枚举其可以过去的点,然后结果为111的点连接汇点,直接跑一次dinic就得出最大结果了。

这里需要注意的是初始化p为-·,不然就会死循环。

知识点:1、记录每个边刚开始的容量,然后减去跑完dinic的容量,结果就是跑这个dinic这条边通过了多少流量。

2、n种饮料和m种吃的喂给牛,牛喂到自己喜欢的就会很开心,问最多牛开心数量,直接建容量为1的边即可

3、n种机子,每种机子连接一个插头,有k个插头,m个调配器,调配期用来相当转接头,每个插头只能用一次,问最少几个机子不能连接,直接就也是模版

4、有n个人,m个房子,问全部人都走到房子的最小花费,预处理出每个人与房子的距离,然后跑最小费用最大流。

#include<cstdio>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=55;
const int Ni = 210;
 const int MAX = 1<<26;
 struct Edge{
     int u,v,c;
     int next;
 }edge[20*Ni];
 int n,m;
 int edn;//边数
 int p[Ni];//父亲
 int d[Ni];
 int sp,tp;//原点,汇点

 void addedge(int u,int v,int c)
 {
     edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
     edge[edn].next=p[u]; p[u]=edn++;

     edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
     edge[edn].next=p[v]; p[v]=edn++;
 }
 int bfs()
 {
     queue <int> q;
     memset(d,-1,sizeof(d));
     d[sp]=0;
     q.push(sp);
     while(!q.empty())
     {
         int cur=q.front();
         q.pop();
         for(int i=p[cur];i!=-1;i=edge[i].next)
         {
             int u=edge[i].v;
             if(d[u]==-1 && edge[i].c>0)
             {
                 d[u]=d[cur]+1;
                 q.push(u);
             }
         }
     }
     return d[tp] != -1;
 }
 int dfs(int a,int b)
 {
     int r=0;
     if(a==tp)return b;
     for(int i=p[a];i!=-1 && r<b;i=edge[i].next)
     {
         int u=edge[i].v;
         if(edge[i].c>0 && d[u]==d[a]+1)
         {
             int x=min(edge[i].c,b-r);
             x=dfs(u,x);
             r+=x;
             edge[i].c-=x;
             edge[i^1].c+=x;
         }
     }
     if(!r)d[a]=-2;
     return r;
 }

 int dinic(int sp,int tp)
 {
     int total=0,t;
     while(bfs())
     {
         //cout <<"~"<< endl;
         while(t=dfs(sp,MAX))
         total+=t;
     }
     return total;
 }
struct ttt{
    int in[12],out[12];
    int sp;
};
ttt qq[maxn];
int q1[2505];
int main(){
    //freopen("in.txt","r",stdin);
    int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
    int T;
    int s,t;
    //freopen("in.txt","r",stdin);
    cin >>n>> m;
    sp=0;tp=m+1;
    memset(p,-1,sizeof(p)); //时刻记住Dinic的初始化p
    for(i=1;i<=m;i++){ //有m个机器,n个零件
    cin  >> qq[i].sp;
    for(j=1;j<=n;j++)
        cin >> qq[i].in[j];
    for(j=1;j<=n;j++)
        cin >> qq[i].out[j];
    }
    int tot=0;
    for(i=1;i<=m;i++){
        for(j=1;j<=m;j++){
            if(i==j)continue;
            f1=0;
            for(k=1;k<=n;k++)
            if(qq[i].out[k]+qq[j].in[k]==1)f1=1;
            if(f1==0){
                addedge(i,j,min(qq[i].sp,qq[j].sp));//这里这个min,尽量正确的约束条件越多越好,
                q1[tot++]=min(qq[i].sp,qq[j].sp);
            }
        }
    }
    for(i=1;i<=m;i++){
        f1=1;f2=1;
        for(j=1;j<=n;j++){
            if(qq[i].in[j]==1)f1=0;
            if(qq[i].out[j]==0)f2=0;
        }
        if(f1){ //表面源点连过去
            addedge(sp,i,qq[i].sp);
        }
        if(f2){
            addedge(i,tp,qq[i].sp);
        }
    }
   // cout << sp <<"   "<<tp << endl;
   t1=0;
   f1=dinic(sp,tp);
    for(i=0;i<tot;i++){
        if(q1[i]>edge[i+i].c){
                t1++;
        }
    }
      printf("%d %d\n",f1,t1);
    for(i=0;i<tot;i++){
        if(q1[i]>edge[i+i].c){
                t1++;
            printf("%d %d %d\n",edge[i+i].u,edge[i+i].v,q1[i]-edge[i+i].c);
        }
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值