题目描述:
Alice上化学课时又分心了,他首先画了一个3行N列的表格,然后把数字1到N填入表格的第一行,保证每个数只出现一次,另外两行他也填入数字1到N,但不限制每个数字的出现次数。Alice现在想删除若干列使得每一行排完序后完全一样,编程计算最少需要删除多少列。
输入:第一行包含一个整数N(1<=N<=100000),表示表格的列数。接下来三行每行包含N个整数,每个数在1到N之间,而且第一行的数互不相同。
输出:输出最少需要删除的列数。
【思路解析】
首先我们注意到红字部分的3行N列,它只有三行,所以我们可以直接手动处理输入:lin1/2/3[i] 表示的是第1/2/3行的第i列的数字,sum2/3[]表示的是第2,3行每个数(1-n中)出现的次数,然后我们就可以循环的去判断:如果可以下面两行有某些数出现次数为0,那么第一行的对应的数一定要删除,否则不可能完全一样,当这一列删除后可能还会导致下面两行另外的数出现的个数变为0的情况,我们可以在外面写一个do-while循环,当所有列都删完或者后两行元素都和第一行一致后,结束循环并输出答案。在while中我们可以写一个for循环从1-n(枚举第i列),如果该列已经被删掉或者该列的第一行的数下面两行都有(不需要删除)的话就跳过,反之则删除这一列:答案数加1,后面两行在这一列的数出现的个数-1,然后要把第一行该列的数记为0(以此为判断条件以便下一次循环时可以直接判断这一列是否已经删除)并且将bool变量的值定为真,说明在这一次循环中进行了操作,循环继续(注意,一定要在while循环头部把bool变量的值还原为0,否则会陷入死循环)。最后退出循环,输出答案 。
Code:
#include<iostream> #include<cstdio> using namespace std; int lin1[100001]={0},lin2[100001]={0},lin3[100001]={0}; int num2[100001]={0},num3[100001]={0}; int n,dele=0,ans=0; int main(){ ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=3;i++){ for(int j=1;j<=n;j++){ if(i==1) cin>>lin1[j]; else if(i==2) cin>>lin2[j],num2[lin2[j]]++; else if(i==3) cin>>lin3[j],num3[lin3[j]]++; } } do{ dele=0; for(int i=1;i<=n;i++){ if(lin1[i]&&((!num2[lin1[i]])||(!num3[lin1[i]]))){ ans++; lin1[i]=0; num2[lin2[i]]--; num3[lin3[i]]--; dele=1; } } }while(dele); cout<<ans; }