• UVa10779


    题目链接

    简介:交换贴纸

    分析:
    这也算是一个天坑了
    很久之前就看过这道题,但是一直没有填

    美妙的建图:
    我们用n-1个点表示每个除Bob之外的人
    用m个点表示贴纸,从源点向这m个点连边,边的容量是Bob拥有该种贴纸的数量

    接下来我们要连接其他人和贴纸:
    如果第i个人有超过一张j种贴纸(有k张),那么我们就连接i—>j,容量为k-1,表示ta可以贡献出k-1张第j种贴纸
    如果第i个人没有第j种贴纸,那么我们连接j—>i,容量为1,表示ta最多接受一张j贴纸

    最后所有的贴纸连向汇点,流量为1

    最大流即为最后答案

    附样例图:
    这里写图片描述

    //这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<queue>
    
    using namespace std;
    
    const int N=101;
    const int INF=0x33333333;
    struct node{
        int x,y,v,nxt;
    };
    node way[N*N];
    int st[N],tot,deep[N],cur[N],s,t;
    int n,m,zl[30][30];
    
    void add(int u,int w,int z)
    {
        tot++;
        way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
        tot++;
        way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].nxt=st[w];st[w]=tot;
    }
    
    int bfs(int s,int t)
    {
        for (int i=s;i<=t;i++) cur[i]=st[i];
        memset(deep,-1,sizeof(deep));
        queue<int> Q;
        Q.push(s);
        deep[s]=1;
    
        while (!Q.empty())
        {
            int now=Q.front(); Q.pop();
            for (int i=st[now];i!=-1;i=way[i].nxt)
                if (way[i].v&&deep[way[i].y]==-1)
                {
                    deep[way[i].y]=deep[now]+1;
                    Q.push(way[i].y);
                }
        }
        return deep[t]!=-1;
    }
    
    int dfs(int now,int t,int limit)
    {
        if (now==t||!limit) return limit;
        int f,flow=0;
        for (int i=cur[now];i!=-1;i=way[i].nxt)
        {
            cur[now]=i;
            if (way[i].v&&deep[way[i].y]==deep[now]+1&&(f=dfs(way[i].y,t,min(limit,way[i].v))))
            {
                flow+=f;
                limit-=f;
                way[i].v-=f;
                way[i^1].v+=f;
                if (!limit) break;
            }
        }
        return flow;
    }
    
    int dinic()
    {
        int ans=0;
        while (bfs(s,t))
            ans+=dfs(s,t,INF);
        return ans;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        for (int cas=1;cas<=T;cas++)
        {
            memset(st,-1,sizeof(st));
            tot=-1;
    
            scanf("%d%d",&n,&m);
            memset(zl,0,sizeof(zl));
            for (int i=1;i<=n;i++)
            {              
                int k,x;                                     //input
                scanf("%d",&k);
                for (int l=1;l<=k;l++)
                    scanf("%d",&x),zl[i][x]++;
            }
    
            s=0; t=n+m+1;
    
            for (int i=1;i<=m;i++)
            {
                if (zl[1][i]) add(s,i,zl[1][i]);
                add(i,t,1);
            } 
            for (int i=2;i<=n;i++)
                for (int j=1;j<=m;j++)
                {
                    if (zl[i][j]>1)              //可以给出一张j 
                        add(i+m,j,zl[i][j]-1);
                    if (!zl[i][j])               //没有j,最多可以接受一张j 
                        add(j,i+m,1);
                }
    
            printf("Case #%d: %d
    ",cas,dinic());
        }   
        return 0;
    }
  • 相关阅读:
    熟悉常用的HDFS操作
    爬虫大作业-爬取B站弹幕
    数据结构化与保存
    使用正则表达式,取得点击次数,函数抽离
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    综合练习:词频统计
    理解MapReduce
    熟悉常用的HBase操作
    熟悉常用的HDFS操作
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673028.html
Copyright © 2020-2023  润新知