思路:题目描述的大致意思就是:给定n张牌,每张牌分成正面和反面,正面和反面都涂有颜色(颜色用数字代替),每次可以翻动一张牌,使得一张牌的另一面朝上,这样问需要最少翻动多少次才能使得不少于n/2张牌的颜色相同,如果没有答案的话,则输出-1.
这道题的做法有两种:(1)记录每张牌的正面和反面,并记录它们出现的次数,当某个颜色的在正面出现次数和在反面的出现次数>=n/2时,那么就找到一种满足情况,遍历所有的颜色,找出最小的一种就行了。(使用STL中的map记录)
(2)使用结构体数组,记录每张牌的正面和反面的颜色,并记录他们处于正面还是反面,然后再使用sort对颜色大小排序,之后遍历所有颜色,当某种颜色出现次数>=n/2时,这样就找到满足情况的颜色,依次类推,找到最小的情况即可。
特殊注意:有些牌的正面颜色和反面颜色相同,那么只需要记录其正面即可。还有当某个颜色处于正面的次数>=n/2时,直接输出0即可。
分别给出两种思路的代码:
第一种:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
struct node
{
int l,r;
} ;
map<int,node>hash;
int s[200009];
int main()
{
int n;
scanf("%d",&n);
int i,x,y,k=0;
for(i=0; i<n; i++)
{
scanf("%d%d",&x,&y);
if(x!=y)
{
hash[x].l++;
hash[y].r++;
s[k++]=x;
s[k++]=y;
}
else hash[x].l++,s[k++]=x;
}
int l=-1;
for(i=0; i<k; i++)
if(hash[s[i]].l+hash[s[i]].r>=(n+1)/2)
{
if(hash[s[i]].l>=(n+1)/2)
{
l=0;
break;
}
else
{
if(l==-1) l=(n+1)/2-hash[s[i]].l;
else l=min(l,(n+1)/2-hash[s[i]].l);
}
}
printf("%d\n",l);
return 0;
}
第二种:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
int x;
int m;
} s[201000];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int n;
while(scanf("%d",&n)!=-1)
{
int k=0;
int a,b;
for(int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
if(a!=b)
{
s[k].x=a;
s[k++].m=0;
s[k].x=b;
s[k++].m=1;
}
else
{
s[k].x=a;
s[k++].m=0;
}
}
sort(s,s+k,cmp);
//for(int i=0;i<k;i++)
// printf("%d %d\n",s[i].x,s[i].m);
int l=-1,ans=0;
int i,j=0;
for(i=0;i<k;i=j)
{
if(s[i].m)
ans=0;
else ans=1;
for(j=i+1;j<k&&s[i].x==s[j].x;j++)
if(s[j].m==0) ans++;
if(j-i>=(n+1)/2)
{
if(ans>=(n+1)/2)
{
l=0;i=k;j=k;break;
}
else
{
if(l==-1) l=(n+1)/2-ans;
else l=min(l,(n+1)/2-ans);
}
}
}
printf("%d\n",l);
}
return 0;
}