集装箱运输货物时,我们必须特别小心,不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱,否则很容易造成爆炸。
本题给定一张不相容物品的清单,需要你检查每一张集装箱货品清单,判断它们是否能装在同一只箱子里。
输入格式:
输入第一行给出两个正整数:N (≤104) 是成对的不相容物品的对数;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
思路分析:
用二维数组——即图去判断两对物品是否是危险品对,可能很多人尝试过内存超出了限制,
其实如果只是判断2物品是否互为危险品,只需要一个二进制位(0/1)就可以判断,因此
可以使用占内存容量最小的char数组来存放图中的每2个物品的信息,若互为危险品则对应
位置为1,否则为0。由于一个char占1个字节,1个字节由8个二进制位,所有通过除以8就
能得到一共需要多少个char用于存放列信息,之后的操作均基于位运算。
实现代码:
#include<stdio.h>
#include<stdlib.h>
#define N 10000
int sum1,sum2,size,*NumNumber;
unsigned char** tu;
const char* jg[100];
const char* y="Yes";
const char* n="No";
int compare(const void *,const void *);
int search(int [],int,int,int);
int main(){
int i,j,k,temp1,temp2,ls1[N],ls2[N],no[2*N],quchong[2*N],nocount=0,qccount=0;
int inx1,inx2;
scanf("%d %d",&sum1,&sum2);
for(i=0;i<sum1;i++){//获取危险物品对的编号
scanf("%d%d",&temp1,&temp2);
ls1[i]=temp1;//存放危险物品左边输入的编号
no[nocount++]=temp1;//存放以上危险对的编号
ls2[i]=temp2;//存放危险物品右边输入的编号
no[nocount++]=temp2;//存放以上危险对的编号
}
qsort(no,nocount,sizeof(int),compare);//对所有输入危险对编号进行排序
inx1=-1;
for(i=0;i<nocount;i++){//去除重复的输入,提取出危险物品对的唯一编号
if(inx1!=no[i]){
quchong[qccount++]=no[i];
inx1=no[i];
}
}
size=(qccount%8==0)?(qccount/8):(qccount/8+1);//计算需要多少个字节才能容纳图的所有二进制位
tu=(unsigned char**)malloc(sizeof(unsigned char*)*qccount);//分配行指针
for(i=0;i<qccount;i++){
*(tu+i)=(unsigned char*)malloc(sizeof(unsigned char)*size);//分配列指针
}
NumNumber=(int*)malloc(sizeof(int)*qccount);//呈现升序排序的输入对编号,用于使用二分法搜素
for(i=0;i<qccount;i++){
*(NumNumber+i)=quchong[i];
}
for(i=0;i<qccount;i++){//初始化图
for(j=0;j<size;j++){
*(*(tu+i)+j)=0;
}
}
for(i=0;i<sum1;i++){//使用位运算进行图中位置的赋值
inx1=search(NumNumber,0,qccount,ls1[i]);
inx2=search(NumNumber,0,qccount,ls2[i]);
*(*(tu+inx1)+inx2/8)=*(*(tu+inx1)+inx2/8) | (0x80>>(inx2%8));
*(*(tu+inx2)+inx1/8)=*(*(tu+inx2)+inx1/8) | (0x80>>(inx1%8));
}
int ns[1000];
_Bool ysno;
for(i=0;i<sum2;i++){//遍历输入对
scanf("%d",&temp1);
for(j=0;j<temp1;j++){
scanf("%d",&ns[j]);
}
ysno=1;
for(j=0;j<temp1-1 && ysno;j++){
inx1=search(NumNumber,0,qccount-1,ns[j]);
if(inx1==-1){
continue;
}
for(k=j+1;k<temp1;k++){
inx2=search(NumNumber,0,qccount-1,ns[k]);
if(inx2!=-1){
if((*(*(tu+inx1)+inx2/8) & (0x80>>(inx2%8))) || (*(*(tu+inx2)+inx1/8) & (0x80>>(inx1%8)))){//跟图中的位置比较,判断两节点是否连接
ysno=0;
break;
}
}
}
}
if(ysno){
jg[i]=y;
}
else{
jg[i]=n;
}
}
for(i=0;i<sum2;i++){
printf("%s\n",jg[i]);
}
}
int compare(const void *p1,const void *p2){
const int *a=(const void *)p1;
const int *b=(const void *)p2;
if(*a>*b){
return 1;
}
else if(*a<*b){
return -1;
}
else{
return 0;
}
}
int search(int num[],int l,int r,int v){
int m;
while(r>=l){
m=(r+l)/2;
if(num[m]==v){
return m;
}
if(num[m]>v){
r=m-1;
}
else{
l=m+1;
}
}
return -1;
}