爆刷PAT(甲级)——之【1139】 First Contact (30 分)——模拟+两个细节

题意:N个小朋友,告诉你他们的朋友关系。K次询问,对每次询问回答有几种告白方式。告白的方法是——A喜欢B,那么A要找邻接点C,C找邻接点D,D告诉他的朋友B实现告白。要求A和B同性别,C和D同性别,A和B不一定。人数N小于300,询问K小于100.输出所有可行的C和D,按照升序输出。

思路:思路可以想到,列举一下A的所有朋友,列举一下B的所有朋友,然后看看他们各自的朋友有几对朋友即可。但是我写的太慢太复杂了。。。晕死,也懒得改了。

难点:这题的按照上书写了之后只拿到20分。。。我也没想到啥原因。看了柳神的博客学习之后,恍然大悟,发现本题有两个细节情况必须要讨论!

1、判断性别的时候如果ID是0000,按照数字读入就会没办法判断此人的性别。所以只能用字符串输入的形式。这样就能过第二个样例,多得4分。

2、A要像B告白的话,在建A的朋友列表的时候,必须要排除B。。。这个点考虑就能过另外三个点,加6分。

本题考查编码习惯、思考细节方面很不错,码一下留个纪念。

Code:

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define inf 309
#define INF 0x3f3f3f3f
#define loop(x,y,z) for(x=y;x<z;x++)

int n,m,k;
unordered_map<int,int>mp;
unordered_map<int,int>mp2;
bool isboy[inf];
int e[inf][inf];

int stoi(string &s1)//Codeblocks不支持,手写一下
{
    const char *s=s1.c_str();
    int len=s1.length();
    int flag=1;
    if(s1[0]=='-')flag=0;
    int sum=0,i=0;
    if(!flag)i++;
    for(i;i<len;i++)
        sum=sum*10+s[i]-48;
    if(!flag)sum*=-1;
    return sum;
}

bool cmp(pair<int,int>&x,pair<int,int>&y)
{
    if(mp2[x.first]==mp2[y.first])return mp2[x.second]<mp2[y.second];
    return mp2[x.first]<mp2[y.first];
}
void findAns(int x,int y)
{
    int sum=0,i,j;
    vector<int>left;
    left.clear();
    vector<int>right;
    right.clear();
    vector< pair<int,int> >ans;
    ans.clear();

    loop(i,1,n+1)if(e[x][i]&&i!=y&&isboy[x]==isboy[i])left.push_back(i);
    loop(i,1,n+1)if(e[y][i]&&i!=x&&isboy[y]==isboy[i])right.push_back(i);
    loop(i,0,left.size())
    loop(j,0,right.size())
    {
        int u=left[i];
        int v=right[j];
        if(e[u][v]&&((isboy[x]==isboy[y]&&isboy[u]==isboy[v])||(isboy[x]!=isboy[y]&&isboy[u]!=isboy[v])))
        {
            sum++;
            ans.push_back(pair<int,int>(u,v));
        }
    }
    printf("%d\n",sum);
    if(!sum)return;
    sort(ans.begin(),ans.end(),cmp);
    loop(i,0,ans.size())
    printf("%04d %04d\n",mp2[ans[i].first],mp2[ans[i].second]);
}

int main()
{
    int i,j;
    int x,y;
    scanf("%d%d",&n,&m);
    int id=1;
    loop(i,0,m)
    {
        bool flag1=1,flag2=1;
        string s1,s2;
        cin>>s1>>s2;
        int x=stoi(s1);
        int y=stoi(s2);
        if(s1[0]=='-'){flag1=0;x=-x;}
        if(s2[0]=='-'){flag2=0;y=-y;}
        if(mp.count(x))x=mp[x];
        else
        {
            mp[x]=id;
            mp2[id]=x;
            x=mp[x];
            id++;
        }

        if(mp.count(y))y=mp[y];
        else
        {
            mp[y]=id;
            mp2[id]=y;
            y=mp[y];
            id++;
        }
        isboy[x]=flag1;
        isboy[y]=flag2;
        e[x][y]=e[y][x]=1;
    }
    scanf("%d",&k);
    while(k--)
    {
        scanf("%d%d",&x,&y);
        x=x<0?-x:x;
        y=y<0?-y:y;
        x=mp[x];
        y=mp[y];
        findAns(x,y);
    }

    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值