PAT B 1090 危险品装箱(C语言)*较高效

一、题目

集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸。

本题给定一张不相容物品的清单,需要你检查每一张集装箱货品清单,判断它们是否能装在同一只箱子里。

输入格式:
输入第一行给出两个正整数:N (≤10^​4​​ ) 是成对的不相容物品的对数;M (≤100) 是集装箱货品清单的单数。
随后数据分两大块给出。第一块有 N 行,每行给出一对不相容的物品。第二块有 M 行,每行给出一箱货物的清单
格式如下:
K G[1] G[2] … G[K]
其中 K (≤1000) 是物品件数,G[i] 是物品的编号。简单起见,每件物品用一个 5 位数的编号代表。两个数字之间用空格分隔。

输出格式:
对每箱货物清单,判断是否可以安全运输。如果没有不相容物品,则在一行中输出 Yes,否则输出 No。

输入样例:
6 3
20001 20002
20003 20004
20005 20006
20003 20001
20005 20004
20004 20006
4 00001 20004 00002 20003
5 98823 20002 20003 20006 10010
3 12345 67890 23333

输出样例:
No
Yes
Yes

作者: CHEN, Yue
单位: 浙江大学
时间限制: 400 ms
内存限制: 64 MB
代码长度限制: 16 KB

二、思路

这道题效率最高的方法应该是使用十字链表
但是懒癌晚期…
思路是一样的,最下面修改前的代码思路更为清晰一些

主要思路:
建立一个与某物品不相容的清单

如给定6对互不相容的物品:

20001 20002
20003 20004
20005 20006
20003 20001
20005 20004
20004 20006

将一对中第一个重复的合并,得到:
20001 20002
20003 20004 20001
20005 20006 20004
20004 20006

然后对给定的一箱物品检查有无相排斥的物品出现就可以了。

/*附:
其实最初想法是将一对互斥物品的左右两个物品都建立数组保存的
即得到:
20001 20002 20003
20002 20001
20003 20004 20001
20004 20003 20005 20006
20005 20006 20004
20006 20005 20004
但是想想这样赋值两次是不是虽然看起来更稳妥,但是完全没必要的啊。只记录一对中的第一个的不相容物品就可以达到检测的目的了。
(语言表达能力和代码逻辑都不太好…大家尽量自己悟一下)

继续…
第一次尝试建立的数组过大,出现段错误
改的时候随便给数组赋了个2,代码绝对是错的,居然AC了…瞎猫碰上死耗子冠军…
(老师!测试点有空子可钻!!)
但是我不死心,对代码进行了改进。

两次代码比较后发现!
增加一次qsort后代码效率并没有太大变化

快速排序是好东西!
用好排序很有用!

在这里插入图片描述
耗时29ms!满意!应该是比其他方法都快的

三、代码实现

#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a,const void *b)//升序(其实无球的所谓)
{
    int *p=(int *)a,*q=(int *)b;
    return *p-*q;
}
int main()
{
    int M,N,i,j,k,l,Index[100000][2]={0,0},Num,Max,a1,a2,Flag,K,t;
    /*关于Index[][]
     *Index[k][0]:即与编号为k的货物 互不相容的货物 在List数组中存放的位置
     *Index[k][1];即List中存放的 与编号为k的货物互不相容的 货物编号数量
     *例:Index[k][0]==i Index[k][1]==j
     *即为:与 编号为k的货物 互不相容的j个货物存放在 List[i]中。*/
    scanf("%d %d",&N,&M);
    int Conflict[N][2];//存放N对互不相容的货物编号
    for(Max=0,Num=0,i=0 ; i<N ; i++)
    {
        scanf("%d %d",&Conflict[i][0],&Conflict[i][1]);
        if( Index [ Conflict [i] [0] ] [1]++ == 0 )//为避免数组越界,尽量节省空间,记录下共需要建立多少个货物的不相容清单(Num
            Index [ Conflict [i] [0] ] [0] = Num++;
        Max = Max < Index[ Conflict [i] [0] ] [1] ? Index[ Conflict [i] [0] ] [1] : Max;//不相容货物最多有几个(Max
    }
    qsort(Conflict,N,sizeof(Conflict[0]),cmp);//以一对中的第一个货物编号排序,使相同编号的靠在一起
    int List[Num][Max];//存放不相容的清单
    for(i=0,j=0,k=0 ; i<N ; i++)//存放
    {
        if( Conflict [i] [0] == Conflict [i+1] [0] )
        {
            List [j] [k++] = Conflict [i] [1];
        }
        else
        {
            List [j] [k++] = Conflict [i] [1];
            Index[ Conflict [i] [0] ] [1] = k;
            Index[ Conflict [i] [0] ] [0] = j++;
            k=0;
        }
    }
    for(i=0 ; i<M ; i++)
    {
        scanf("%d",&K);
        int G[K],T[100000]={0};
        for(j=0 ; j<K ; j++)//将第i箱货物赋1
        {
            scanf("%d",&G[j]);
            T[G[j]]++;
        }
        for(Flag=0,j=0 ; j<K && Flag==0 ; j++)
            for(k=0 ; k < Index[G[j]][1] && Flag==0 ; k++)//检测有没有互不相容的货物
                    if( T[List[ Index[G[j]][0] ][k]] > 0 )
                        Flag=1;
            printf("%s\n",Flag ? "No" : "Yes");
    }
    return 0;
}

附:修改前代码

#include <stdio.h>
int main()
{
    int M,N,i,j,k,l,Count[100000]={0},a1,a2,Flag,K;
    scanf("%d %d",&N,&M);
    int List[100000][2];
  	/*此处错误:数据量大的时候不可能保证最多仅两个不相容物*/
    for(i=0 ; i<N ; i++)
    {
        scanf("%d %d",&a1,&a2);
        List[a1][Count[a1]++] = a2;
    }
    for(i=0 ; i<M ; i++)
    {
        scanf("%d",&K);
        int G[K],Temp[100000]={0};
        for(j=0 ; j<K ; j++)
        {
            scanf("%d",&G[j]);
            Temp[G[j]]++;
        }
        for(Flag=0,j=0 ; j<K && Flag==0 ; j++)
            for(k=0 ; k<Count[G[j]] && Flag==0 ; k++)
                    if( Temp[List[G[j]][k]] > 0 )
                        Flag=1;
            printf("%s\n",Flag ? "No" : "Yes");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值