zoukankan      html  css  js  c++  java
  • 2015 编程之美 八卦的小冰

    题目3 : 八卦的小冰

    时间限制:2000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    小冰是个八卦的人,最近她对一个社交网站很感兴趣。

    由于小冰是个机器人,所以当然可以很快地弄清楚这个社交网站中用户的信息啦。

    她发现这个社交网站中有N个用户,用户和用户之间可以进行互动。小冰根据用户之间互动的次数和内容判断每对用户之间的亲密度。亲密度非负,若大于零表示这两个用户之间是好友关系。由于这个网站是活跃的,所以小冰会不停地更新用户之间的亲密度。

    由于隐私保护,小冰无法知道每个用户的确切性别,但是作为一只很聪明的人工智能,小冰可以通过每个用户的行为来猜测性别。当然这种猜测是不准确的,小冰有可能会改变对一个用户的判断。

    小冰想知道这个社交网络的八卦度是多少。八卦度的定义是社交网络中所有异性好友之间的亲密度之和。你能帮助她吗?

    输入

    第一行一个整数T,表示数据组数。接下来是T组数据,每组数据的格式如下:

    第一行是三个整数N, M, Q,分别表示用户数、初始的好友对数、操作数。

    第二行是N个空格隔开的数,第i个数表示i号用户的性别,用0或1表示。

    接下来的M行,每行三个数x, y, z,代表初始状态用户x和用户y之间的亲密度是z。除此之外的用户之间的亲密度初始为0。

    接下来是Q行,每行是以下三种操作中的一种:

    1. “1 x”:改变用户x的性别

    2. “2 x y z”:改变用户x与用户y之间的亲密度为z

    3. “3”:询问八卦度

    输出

    对于每组数据首先输出一行"Case #X:",X为测试数据编号。

    接下来对于每一个询问,输出一行包含询问的八卦度。

    数据范围

    1 ≤ T ≤ 20

    1 ≤ x, y ≤ N

    0 ≤ z ≤ 100000

    小数据

    1 ≤ N, M ≤ 100

    1 ≤ Q ≤ 1000

    大数据

    1 ≤ N, M, Q ≤ 100000

    样例输入
    1
    3 2 8
    0 1 0
    1 2 1
    1 3 1
    3
    1 1
    1 2
    3
    2 2 3 2
    3
    1 2
    3
    
    样例输出
    Case #1:
    1
    2
    2
    3
    
     
       题意:构建无向图,成员编号是1~N,每个成员当作一个点,而且每个成员有分男女性别,在这无向图中,每一条边表示两个成员之间的亲密度,询问异性之间亲密度的总和。一开始让如每一个成员的性别用 0 1表示,在输入初始化的无向图。输入操作数1 x,表示改变x编号成员的性别,输入操作数2 x y z,表示改变编号x和编号y的亲密度为z,输入操作数3 ,询问异性之间亲密度的总和,在于题目的大数据点和边都比较大,用临街矩阵做不了,需要采用的是用邻接表来实现记录无向图。
      题目的难点在于对于每一次的询问,如果都要进行查找,则会超时。
      1,所以,用sum来记录异性亲密度总和,在初始的无向图时,判断下性别,累加异性的亲密度。
      2,在修改性别也同样更新sum,因为改变性别的,结果只是会影响到与该点所连接的亲密度是否需要累加,
        a,如果修改后性别一样,说明之前性别不一样,也就是之前就有加过这个顶点的权值了,而且,现在性别一样,所以sum需要减去这顶点的的权值来实现更新;
         b,如果修改后性别不一样,说明之前的性别一样,也就是之前没有加上该顶点的权值,现在性别不一样,所以,sum直接加上当前顶点的权值来实现更新;
      3,如果修改的是两个成员的关系,则有可能是添加新的边或者是修改已经有的点的权值。如果是修改已有边的权值需要你去查找改变,并且更新sum,如果是新建边,则只需要继续累加sum即可;
      4,题目中的边数量可能会比较大,在操作的时候,可能一直添加边,提交结果有时候确实TLE而不是RE,囧囧囧。。。
      PS:链表的边数=无向图边数*2,这个忘记了导致出错,判断居然还是提示TLE而不是RE,囧囧囧囧。。。
      一下代码使用两种方法记录答案,一个是按照边数记录,一个是按照链表的边数记录;
      1 /*记录无向图的边数*/
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #define MAX 100010
      6 using namespace std;
      7 int SEX[100010];    //性别
      8 typedef struct edge
      9 {
     10     int TO;     //下一个顶点
     11     int Next;   //记录下一条边的编号
     12     int Vlaue;  //权值
     13 }EDGE;
     14 EDGE ID[3*MAX];   //边表,坑爹的边数,记得弄多点,不然有时候也会提示超时。
     15 int First[MAX]; //First[x]:x表示头结点为x,First[x]表示下一条边的编号
     16 int SIGN;
     17 long long sum;
     18 void Add_E(int x,int y,int z)   //添加边
     19 {
     20     ID[SIGN].TO=y;
     21     ID[SIGN].Vlaue=z;
     22     ID[SIGN].Next=First[x];
     23     First[x]=SIGN++;
     24 }
     25 
     26 void C_SEX()
     27 {
     28     int n,i;
     29     scanf("%d",&n);
     30     SEX[n]=1-SEX[n];        //改变性别
     31     for(i=First[n];i!=0;i=ID[i].Next)   //查找与该点相关的点
     32     {
     33         if(SEX[ID[i].TO]==SEX[n])    //与修改后的性别一样,
     34         {                            //说明之前是加上该点的权值,
     35             sum-=ID[i].Vlaue;      //减去该点的权值
     36         }
     37         else
     38         {                            //与修改后的性别不一样
     39             sum+=ID[i].Vlaue;      //说明之前是没有加上该点的权值,
     40         }                            //现在就加上该点的权值
     41     }
     42     return ;
     43 }
     44 void C_Map()
     45 {
     46     int x, y, z,i,Begin=0;
     47     scanf("%d %d %d",&x,&y,&z);
     48     for(i=First[x];i!=0;i=ID[i].Next)//查找是否已经存在的关系
     49     {
     50         if(ID[i].TO==y)//存在关系
     51         {
     52             Begin=ID[i].Vlaue;
     53             ID[i].Vlaue=z;
     54             break;
     55         }
     56     }
     57     if(i!=0)
     58     {
     59         for(i=First[y];i!=0;i=ID[i].Next)//查找是否已经存在的关系
     60         {
     61             if(ID[i].TO==x)//存在关系
     62             {
     63                 ID[i].Vlaue=z;
     64                 break;
     65             }
     66         }
     67     }
     68     else if(i==0)//如果没有存在关系,创建两个点
     69     {
     70         Add_E(x,y,z);
     71         Add_E(y,x,z);
     72     }
     73     if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值
     74         sum+=(z-Begin);
     75 
     76     return ;
     77 }
     78 
     79 void FIND()//输出答案
     80 {
     81     printf("%lld
    ",sum);
     82     return ;
     83 }
     84 void work()
     85 {
     86     int N;
     87     scanf("%d",&N);
     88     switch(N)
     89     {
     90         case 1:C_SEX();break;
     91         case 2:C_Map();break;
     92         case 3:FIND();break;
     93     }
     94     return ;
     95 }
     96 int main()
     97 {
     98    int T,i,t;
     99    int N,M,Q;
    100    int x,y,z;
    101    scanf("%d",&T);
    102    t=1;
    103    while(T--)
    104    {
    105         scanf("%d %d %d",&N,&M,&Q);
    106         SIGN=1;sum=0;
    107         for(i=1;i<=N;i++)
    108         {
    109             scanf("%d",&SEX[i]);
    110             First[i]=0;
    111         }
    112         for(i=1;i<=M;i++)
    113         {
    114             scanf("%d %d %d",&x,&y,&z);
    115             Add_E(x,y,z);
    116             Add_E(y,x,z);
    117             if(SEX[x]!=SEX[y])sum+=z;   //判断性别不一样相加
    118         }
    119         printf("Case #%d:
    ",t++);
    120         while(Q--)
    121         {
    122             work();
    123         }
    124    }
    125    return 0;
    126 }
    View Code
      1 /*按照链表的边数记录*/
      2 #include <iostream>
      3 #include <stdio.h>
      4 #include <string.h>
      5 #define MAX 100010
      6 using namespace std;
      7 int Len;            //人数
      8 int SEX[100010];    //性别
      9 typedef struct edge
     10 {
     11     int TO;     //下一个顶点
     12     int Next;   //记录下一条边的编号
     13     int Vlaue;  //权值
     14 }EDGE;
     15 EDGE ID[3*MAX];   //边表,坑爹的边数记得多弄些,不然有可能会TLE
     16 int First[MAX]; //First[x]:x表示头结点为x,First[x]表示下一条边的编号
     17 int SIGN;
     18 long long sum;
     19 void Add_E(int x,int y,int z)   //添加边
     20 {
     21     if(SEX[x]!=SEX[y])sum+=z;   //判断性别不一样相加
     22     ID[SIGN].TO=y;
     23     ID[SIGN].Vlaue=z;
     24     ID[SIGN].Next=First[x];
     25     First[x]=SIGN++;
     26 }
     27 
     28 void C_SEX()
     29 {
     30     int n,i;
     31     scanf("%d",&n);
     32     SEX[n]=1-SEX[n];        //改变性别
     33     for(i=First[n];i!=0;i=ID[i].Next)   //查找与该点相关的点
     34     {
     35         if(SEX[ID[i].TO]==SEX[n])    //与修改后的性别一样,
     36         {                            //说明之前是加上该点的权值,
     37             sum-=ID[i].Vlaue*2;      //减去该点的权值(无向图)
     38         }
     39         else        
     40         {                            //与修改后的性别不一样
     41             sum+=ID[i].Vlaue*2;      //说明之前是没有加上该点的权值,
     42         }                            //现在就加上该点的权值(无向图)
     43 
     44     }
     45 }
     46 void C_Map()
     47 {
     48     int x, y, z,i;
     49     scanf("%d %d %d",&x,&y,&z);
     50     for(i=First[x];i!=0;i=ID[i].Next)//查找是否已经存在的关系
     51     {
     52         if(ID[i].TO==y)//存在关系
     53         {
     54             if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值
     55                 sum+=(z-ID[i].Vlaue);
     56             ID[i].Vlaue=z;
     57             break;
     58         }
     59     }
     60     if(i!=0)
     61     {
     62         for(i=First[y];i!=0;i=ID[i].Next)//查找是否已经存在的关系
     63         {
     64             if(ID[i].TO==x)//存在关系
     65             {
     66                 if(SEX[x]!=SEX[y])//如果性别不一样,减去之前权值,加上当前的权值
     67                     sum+=(z-ID[i].Vlaue);
     68                 ID[i].Vlaue=z;
     69                 break;
     70             }
     71         }
     72     }
     73     else if(i==0)//如果没有存在关系,创建两个点
     74     {
     75         Add_E(x,y,z);
     76         Add_E(y,x,z);
     77     }
     78 
     79 }
     80 
     81 void FIND()//输出答案
     82 {
     83     printf("%lld
    ",sum/2);//无向图,所以/2;
     84 }
     85 void work()
     86 {
     87     int N;
     88     scanf("%d",&N);
     89     switch(N)
     90     {
     91         case 1:C_SEX();break;
     92         case 2:C_Map();break;
     93         case 3:FIND();break;
     94     }
     95 }
     96 int main()
     97 {
     98    int T,i,t;
     99    int N,M,Q;
    100    int x,y,z;
    101    scanf("%d",&T);
    102    t=1;
    103    while(T--)
    104    {
    105         scanf("%d %d %d",&N,&M,&Q);
    106         Len=N;SIGN=1;sum=0;
    107         for(i=1;i<=N;i++)
    108         {
    109             scanf("%d",&SEX[i]);
    110             First[i]=0;
    111         }
    112         for(i=1;i<=M;i++)
    113         {
    114             scanf("%d %d %d",&x,&y,&z);
    115             Add_E(x,y,z);
    116             Add_E(y,x,z);
    117         }
    118         printf("Case #%d:
    ",t++);
    119         for(i=0;i<Q;i++)
    120         {
    121             work();
    122         }
    123    }
    124    return 0;
    125 }
    View Code
     
    转载请备注:
    **************************************
    * 作者: Wurq
    * 博客: https://www.cnblogs.com/Wurq/
    * Gitee: https://gitee.com/wurq
    **************************************
  • 相关阅读:
    《PHP, MySQL, Javascript和CSS》读书随手记----php篇
    20160917 携程前端笔试题
    总结一下http请求吧
    前端资源池
    【CS】笔试常见题目
    【JavaScript】js 中一些需要注意的问题
    c++中的一些计算的问题
    ubuntu下sqlite命令
    关于ubuntu软件卸载的问题
    【js】关于正则表达式
  • 原文地址:https://www.cnblogs.com/Wurq/p/4463080.html
Copyright © 2011-2022 走看看