ZOJ 3642

Just Another Information Sharing Problem

Time Limit: 2 Seconds      Memory Limit: 65536 KB

There is going to be another test in the kindergarten. Again the teacher has already told every kid some information about the test in advance. This time, all the children share their information with others. But everyone just share some of his information. The teacher want to know how many information someone can get at most.

Input

There are multiple cases, about 50 cases.
The first line of each case contains an integer n, indicating there are n kids.
The following n lines describe the state of the ith student. "Ai Bi Ci x1 x2 ...xAi". The ith kid has Ai distinct information. The information id isx1, x2 ... xAi. He is going to share at leastBi information and at most Ci information. (0 ≤BiCiAi) When some kid share 0 information with others, he is still in the sharing state, and get the information shared by others(Though he doesn't provide anything).
The next line is a number m. You should find how many information kid m can get at most. (1 ≤ m ≤ n)The index of kids is from 1 to n.

n is less than 200, and is positive. The information id is among [1,1000000]. There would be 200 distinct information at most.
The number of information each student carry is among [0,10]. Different kids may carry same information.

Each information can be shared by different kids at the same time.
Output

Just output the number of information that student can get at most.

Sample Input
2
2 1 2 3 4
0 0 0
2
2
2 1 1 5 6
1 1 1 5
2
Sample Output
2
2
Hint

Sample 1: kid 1 shares both information, kid 2 shares nothing. kid 2 can have 2 information.
Sample 2: kid 1 shares (6), kid 2 shares (5). Then kid 2 can have 2 information.


Author: LI, Chao
Contest: ZOJ Monthly, August 2012

 

从源点到每个人连边,容量为这个人能共享的信息的最大数,但源点到目标人的容量要为INF,否则会丢掉目标人原本拥有的信息,从每个人向他拥有的信息连边,容量为1,从每个信息向汇点连边,容量为1,求最大流。

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n;
int pnt_cnt;
int mp[1000005];

#define INF 0x1f1f1f1f
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

#define SIZE 405

int flow[SIZE][SIZE];
int cap[SIZE][SIZE];
int lev[SIZE];
int mn[SIZE];

int que[100000];

//BSF找层次网络,一次寻找多条增广路径
//st最小顶点标号,ed最大顶点标号,src源点标号,tar汇点标号
bool bfs(int st,int ed,int src,int tar)
{
    memset(lev,0x1f,sizeof(lev));

    int front;
    int rear;
    front=rear=0;

    que[front++]=src;
    lev[src]=0;

    while(rear<front)
    {
        int t=que[rear];
        rear++;

        for(int i=st;i<=ed;i++)
        {
            if(cap[t][i]>flow[t][i])
            {
                if(lev[t]+1<lev[i])
                {
                    lev[i]=lev[t]+1;
                    que[front++]=i;
                }
            }
        }
    }
    return lev[tar]<INF;
}

//利用层次网络进行增广,每次DFS寻找的是从该节点出发进行DFS增加的总流量
//mn表示从源点至该节点可增广流量
int dfs(int v,int st,int ed,int src,int tar)
{
    int ret=0;
    if(v==tar)return mn[tar];
    for(int i=st;i<=ed;i++)
    {
        if(mn[v]==0)break;
        if(cap[v][i]>flow[v][i]&&lev[v]+1==lev[i])
        {
            mn[i]=MIN(mn[v],cap[v][i]-flow[v][i]);
            int tt=dfs(i,st,ed,src,tar);
            ret+=tt;
            mn[v]-=tt;//每次修改mn[v]
            flow[v][i]+=tt;
            flow[i][v]-=tt;
        }
    }
    if(ret==0)
    {
        lev[v]=INF;
    }
    return ret;
}

int dinic(int st,int ed,int src,int tar)
{
    int ret=0;
    while(bfs(st,ed,src,tar))//存在可增广路
    {
        memset(mn,0x1f,sizeof(mn));
        int r=dfs(src,st,ed,src,tar);
        if(r==0)break;
        ret+=r;
    }
    return ret;
}

int main()
{
    while(~scanf("%d",&n))
    {
        memset(cap,0,sizeof(cap));
        memset(flow,0,sizeof(flow));
        memset(mp,-1,sizeof(mp));
//0为源点,n+1为汇点
        pnt_cnt=n+2;

        for(int i=1;i<=n;i++)
        {
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            cap[0][i]=c;

            for(int j=1;j<=a;j++)
            {
                int num;
                scanf("%d",&num);
                if(mp[num]==-1)
                {
                    mp[num]=pnt_cnt++;
                }
                cap[i][mp[num]]=1;
                cap[mp[num]][n+1]=1;
            }
        }

        int u;
        scanf("%d",&u);
        cap[0][u]=0x1f1f1f1f;
        int res=dinic(0,pnt_cnt-1,0,n+1);

        printf("%d\n",res);
    }
    return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值