cf534D 枚举握手次数

来源:互联网 发布:如何看待网络暴力演讲 编辑:程序博客网 时间:2024/05/22 15:15
题意:
      有n个学生进教室,先后顺序不同,每个人进去后会和当前在教室里的人握手,并且记录人数,而且当教室里有超过三个人的时候 他们有可能组队去参加比赛,后来的人看不到他们。


思路:

     这个题目还行挺有意思的,我们可以一个人一个人来模拟,就是枚举握手次数,然后在相应的里面找到一个,如果一个都找不到就-3,到最后就行了,比如一开始我们枚举0,就是握手次数是0的,如果找到有0,那么这个人就是第一个人,如果0的不唯一的话随便挑一个就行,找到后就+1,找握手次数为1的,找到后就是第二个进来的,然后+1,找2的...如果当前握手次数找不到的话就-3,找到就继续,还找不到就还-3,这样如果那次当前枚举次数小于0了,那么就说明失败了,就是无解,还有就是找到的时候不能暴力去找,可以用个二维容器什么的,我用的是前向星配合类似DINIC里面那个优化(职业病啊),比如当前i这个人的握手次数是3,那么就连边3->i,这样当我们想在3里面删除的时候随便找一个就行,删除之后记得这样处理 list[s] = E[k].next,就是下次直接从下一个开始就行,这个地方怎么处理都行,顺手就行,用容器还有链表啥的都行,不多说了,关键是想到枚举握手次数的那个地方就好办了。


#include<stdio.h>#include<string.h>#define N_node 200005#define N_edge 250005typedef struct{    int to ,next;}STAR;STAR E[N_edge];int list[N_node] ,tot;int mkc[N_node];int Ans[N_node] ,AT;void add(int a ,int b){    //printf("%d %d**\n" ,a ,b);    E[++tot].to = b;    E[tot].next = list[a];    list[a] = tot;}int main (){    int n ,i ,a ,b;    while(~scanf("%d" ,&n))    {        memset(list ,0 ,sizeof(list)) ,tot = 1;        memset(mkc ,0 ,sizeof(mkc));        for(i = 1 ;i <= n ;i ++)        {            b = i;            scanf("%d" ,&a);            add(a ,b);            mkc[a] ++;        }        int nowc = 0;        AT = 0;        while(nowc >= 0 && AT != n)        {            if(!mkc[nowc]) nowc -= 3;            else            for(int k = list[nowc] ;k ;k = E[k].next)            {                 Ans[++AT] = E[k].to;                 mkc[nowc]--;                 list[nowc] = E[k].next;                 nowc ++;                 break;            }            //printf("%d\n" ,nowc);        }        if(AT == n)        {            printf("Possible\n");            for(i = 1 ;i <= n ;i ++)            if(i == n) printf("%d\n" ,Ans[i]);            else printf("%d " ,Ans[i]);        }        else printf("Impossible\n");    }    return 0;}


0 0
原创粉丝点击