Gym - 101196I-sap+网络流建图

感觉和food题差不多,虽然比赛的时候仍然没有写出来。。
具体要求是先来个 n,m,p
n是小朋友的个数,先来n行
每行第一个是i小朋友喜欢多少种糖,后面是种类。
然后是p个包裹
里面包含有多少种糖
重点来了
Toys can be in
at most one category and any toy not listed in these p lines is not in any toy category and all of them
can be used. No toy number appears more than once on any line
没有被包含的糖小孩子随便吃。
直接sap,啪啪ac
模板很好,
见图是要有顺序的,别xjb见。。。

#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 300+10
#define maxm 90000+10
#define inf 0x3f3f3f3f

using namespace std;

struct Edge
{
    int to,next,cap,flow;
} edge[maxm*2];

int tol;//链式前进行
int head[maxn];//链式前进星
int cur[maxn],d[maxn];//sap
int p[maxn],gap[maxn];//同上
int vis[maxn];//主函数哥哥用。
void init()
{
    tol=0;
    memset(head, -1, sizeof(head));
}

void add(int u,int v,int w,int rw = 0)
{
    edge[tol].to=v;
    edge[tol].cap=w;
    edge[tol].flow=0;
    edge[tol].next=head[u];
    head[u]=tol++;
    edge[tol].to=u;
    edge[tol].cap=rw;
    edge[tol].flow=0;
    edge[tol].next=head[v];
    head[v]=tol++;
}

int Q[maxn];
void bfs(int s,int t)
{
    memset(d, -1, sizeof(d));
    memset(gap, 0, sizeof(gap));
    gap[0]=1;
    int front=0, rear=0;
    d[t]=0;
    Q[rear++]=t;
    while(front!=rear)
    {
        int u=Q[front++];
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v=edge[i].to;
            if(d[v]!=-1)continue;
            Q[rear++]=v;
            d[v]=d[u]+1;
            gap[d[v]]++;
        }
    }
}

int S[maxn];
int sap(int s,int t,int N)
{
    bfs(s, t);
    memcpy(cur, head, sizeof(head));
    int top=0;
    int u=s;
    int ans=0;
    while(d[s]<N)
    {
        if(u==t)
        {
            int Min=inf;
            int inser;
            for(int i=0; i<top; i++)
                if(Min>edge[S[i]].cap-edge[S[i]].flow)
                {
                    Min=edge[S[i]].cap-edge[S[i]].flow;
                    inser=i;
                }
            for(int i=0; i<top; i++)
            {
                edge[S[i]].flow+=Min;
                edge[S[i]^1].flow-=Min;
            }
            ans+=Min;
            top=inser;
            u=edge[S[top]^1].to;
            continue;
        }
        bool ok=false;
        int v;
        for(int i=cur[u]; i!=-1; i=edge[i].next)
        {
            v=edge[i].to;
            if(edge[i].cap-edge[i].flow && d[v]+1==d[u])
            {
                ok=true;
                cur[u]=i;
                break;
            }
        }
        if(ok)
        {
            S[top++]=cur[u];
            u=v;
            continue;
        }
        int Min=N;
        for(int i=head[u]; i!=-1; i=edge[i].next)
            if(edge[i].cap-edge[i].flow && d[edge[i].to]<Min)
            {
                Min=d[edge[i].to];
                cur[u]=i;
            }
        gap[d[u]]--;
        if(!gap[d[u]])return ans;
        d[u]=Min+1;
        gap[d[u]]++;
        if(u!=s)u=edge[S[--top]^1].to;
    }
    return ans;
}


int main()
{  int n,m,p;
int k;
int x;
   while(cin>>n>>m>>p)
   {  init();
       for(int i=1;i<=n;i++)
   { cin>>k;
      for(int j=1;j<=k;j++)
       {   cin>>x;
           add(x,m+i,1);//ren dao wanju

       }
   }

   memset(vis,false,sizeof(vis));
   int kk;
   for(int i=1;i<=p;i++)
   {  cin>>k;
      for(int j=1;j<=k;j++)
      {   cin>>x;
          vis[x]=1;
          add(m+n+i,x,1);//每个包中的玩具,与玩具相连。
      }
      cin>>kk;
      add(0,n+m+i,kk);//每个包裹最多多少,来个流量限制。
   }
  for(int i=1;i<=m;i++)
  {  if(!vis[i])
      add(0,i,1);//剩下的玩具随便玩。
  }
   for(int i=1;i<=n;i++)
     add(i+m,m+n+p+1,1);//孩子与终点。

   //if(bfs(0,m+n+p+1))
    //printf("2111\n");

    printf("%d\n",sap(0,m+n+p+1,m+n+p+2));}
    return 0;
}
/*int main()
{
    int n,m,p,k,t;
    while(cin>>n>>m>>p)
    {
        init();
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            cin>>k;
            for(int j=1;j<=k;j++)
            {
                cin>>t;
                add(m+i,t,1);
            }
        }
        for(int i=1;i<=p;i++)
        {
            cin>>k;
            for(int j=1;j<=k;j++)
            {
                cin>>t;
                vis[t]=1;
                add(m+n+i,t,1);
            }
            cin>>k;
            add(0,m+n+i,k);
        }
        for(int i=1;i<=m;i++)
            if(!vis[i])
                add(0,i,1);
        for(int i=m+1;i<=m+n;i++)
            add(i,m+n+p+1,1);
        cout<<sap(0,m+n+p+1,m+n+p+2)<<endl;
    }
    return 0;
}*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值