SGU 242. Student's Morning

 

 

242. Stud ent's Morning
time limit per test: 1 sec.
memory limit per test: 6144 KB
input: standard
output: standard


One Monday morning after some very fun party N students woke up at the flat of one of them. Notice that it was a Monday morning and every student of that party needs to be in his university this day. But nobody wants to go to his university alone (there were students from different universities). So, they decided to select from all universities only K of them to visit. Every selected university must be visited by at least two of the students. Every student has his own preference list of universities. It means, if some university is in list of some student's preferred universities, this student can go to this university with some non-empty company of students. Notice, that some of students can stay at the flat and continue drinking "juices" and playing "games". For example, student Shokman was to stay home (due to failed exam) with foreign student Chokman, who remained home because of runny nose.
In that problem there are no preferences between students, because if they have very fun party that already means that everyone of them prefers anybody from this company.

More formally, your task is, given numbers of students, selected universities and preference list of every student, to decide whether it is possible to visit all universities by at least two of students or no, and if it is possible you must output for each university numbers of students, which have to go to it in one company. One student can't be in more than one company.

Input
First line of input file contains two numbers N and K (0<=K<=N<=200). Next N lines contain preference lists of each student. Every preference list is started by number of preferred universities followed by numbers of these universities.

Output
First line of output file must contain word "YES" (without quotes), if it possible to visit all universities, satisfying rules of that task or word "NO" (also without quotes) when it is impossible. In case of positive answer next K lines must contain lists of students, who are going to corresponding university. First number in list of students must be a number of students in the list, followed by numbers of these students.

Sample test(s)

Input

Test #1
4 2
1 1
2 1 2
1 2
2 1 2

Test #2
3 2
2 1 2
2 1 2
2 1 2


Output

Test #1
YES
2 1 2
2 3 4

Test #2
NO


Author:Alexey Preobrajensky
Resource:---
Date:October, 2003 

 

 

 

 

 

 

 

 

网上那些用上下界的题解根本不需要那么做

甚至不需要用网络流,23MS,很容易我就用多重匹配过了

首先题目对输出一组解没有任何要求

接着一个学校只要让他去两个人就够了

那么不就是一个很水的多重匹配么

 

写题要多思考,不要想复杂了,多重匹配很多情况还是很好使的

 

 

#include<cstdio>

#include<cstring>

const int INF=0x7fffffff;

int mat[500][500],link[500][500];

bool usedif[500];

int k,n,high;

bool can(int t)

{

    for(int i=1; i<=k; i++)

    {

        if(usedif[i]==0&&mat[t][i])

        {

            usedif[i]=1;

            if(link[i][0]<2)

            {

                link[i][++link[i][0]]=t;

                return true;

            }

            else

            {

                for(int j=1; j<=link[i][0]; j++)

                    if(can(link[i][j]))

                    {

                        link[i][j]=t;

                        return true;

                    }

            }

        }

    }

    return false;

}

 

void MaxMatch()

{

    int num=0;

    for(int i=1; i<=k; i++)  link[i][0]=0;

    for(int i=n; i>=1; i--)

    {

        memset(usedif,0,sizeof(usedif));

        if(!can(i)) num++;

    }

    return ;

}

 

int main()

{

    while(scanf("%d%d",&n,&k)!=EOF)

    {

        memset(mat,false,sizeof(mat));

        for(int i=1;i<=n;i++)

        {

            int x,y;

            scanf("%d",&x);

            for(int j=1;j<=x;j++)

            {

                scanf("%d",&y);

                mat[i][y]=1;

            }

        }

        MaxMatch();

        bool flag=false;

        for(int i=1;i<=k;i++)

        if(link[i][0]<2)

        {

            flag=true;

            break;

        }

        if(!flag)

        {

            printf("YES/n");

            for(int i=1;i<=k;i++)

            {

                printf("%d %d %d/n",link[i][0],link[i][1],link[i][2]);

            }

        }

        else printf("NO/n");

    }

    return 0;

}

 

 

邻接表写的网络流,还行,效率差不多

#include<cstdio>

#include<cstring>

const int N=1510;

const int M=60001;

const int inf=0x7fffffff;

int head[N];

struct Edge

{

    int v,next,w;

} edge[M];

int cnt,n,k,s,t;

void addedge(int u,int v,int w)

{

    edge[cnt].v=v;

    edge[cnt].w=w;

    edge[cnt].next=head[u];

    head[u]=cnt++;

    edge[cnt].v=u;

    edge[cnt].w=0;

    edge[cnt].next=head[v];

    head[v]=cnt++;

}

int sap()

{

    int pre[N],cur[N],dis[N],gap[N];

    int flow=0,aug=inf,u;

    bool flag;

    for(int i=0; i<n; i++)

    {

        cur[i]=head[i];

        gap[i]=dis[i]=0;

    }

    gap[s]=n;

    u=pre[s]=s;

    while(dis[s]<n)

    {

        flag=0;

        for(int &j=cur[u]; j!=-1; j=edge[j].next)

        {

            int v=edge[j].v;

            if(edge[j].w>0&&dis[u]==dis[v]+1)

            {

                flag=1;

                if(edge[j].w<aug) aug=edge[j].w;

                pre[v]=u;

                u=v;

                if(u==t)

                {

                    flow+=aug;

                    while(u!=s)

                    {

                        u=pre[u];

                        edge[cur[u]].w-=aug;

                        edge[cur[u]^1].w+=aug;

                    }

                    aug=inf;

                }

                break;

            }

        }

        if(flag) continue;

        int mindis=n;

        for(int j=head[u]; j!=-1; j=edge[j].next)

        {

            int v=edge[j].v;

            if(edge[j].w>0&&dis[v]<mindis)

            {

                mindis=dis[v];

                cur[u]=j;

            }

        }

        if((--gap[dis[u]])==0)

            break;

        gap[dis[u]=mindis+1]++;

        u=pre[u];

    }

    return flow;

}

int main()

{

    while(scanf("%d%d",&n,&k)!=EOF)

    {

        s=0;

        t=n+k+1;

        cnt=0;

        memset(head,-1,sizeof(head));

        for(int i=1;i<=n;i++)  addedge(s,i,1);

        for(int i=1;i<=k;i++)  addedge(i+n,t,2);

        for(int i=1;i<=n;i++)

        {

            int x,y;

            scanf("%d",&x);

            for(int j=1;j<=x;j++)

            {

                scanf("%d",&y);

                addedge(i,y+n,1);

            }

        }

        int nn=n;

        n=n+k+2;

        if(sap()==k*2)

        {

            printf("YES/n");

            for(int j=1+nn;j<=k+nn;j++)

            {

              printf("2");

              for(int p=head[j];p!=-1;p=edge[p].next)

              {

                  int v=edge[p].v;

                  if(v==t)  continue;

                  int w=edge[p].w;

                  if(w!=0) printf(" %d",v);

              }

              printf("/n");

            }

        }

        else  printf("NO/n");

    }

    return 0;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值