zoukankan      html  css  js  c++  java
  • 第46套题【STL】【贪心】【递推】【BFS 图】

      已经有四套题没有写博客了。今天改的比较快,就有时间写。今天这套题是用的图片的形式,传上来不好看,就自己描述吧。


    第一题:单词分类

      题目大意:有n个单词(n<=10000),如果两个单词中每个字母的数量是一样的(比如:AABAC 和BCAAA)则为一类单词,每个单词长度不大于100,问这些单词可以分为几类?

      样例:输入:3  AABCA AAABC BBCAA    输出:2

      题解:

      每次都在第一题是字符串的时候卡住,这次又卡了一个多小时。。一般思路,就是枚举查找,排序,然后一个一个的比较,但是只过了一半,WA了一半。这个时候,根据每一类单词按字母序排序后都是一模一样的就可以用STL 中的set,将单词按字母序排序后存入set,最后输出 s.size() 。关键是对字符串进行排序 sort(st.begin() , st.end())

      参考代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<set>
     4 #include<algorithm>
     5 using namespace std;
     6 set<string> t;
     7 int n;
     8 int main()
     9 {
    10     freopen("word.in","r",stdin);
    11     freopen("word.out","w",stdout);
    12     cin>>n;
    13     for (int i=1;i<=n;i++)
    14     {
    15         string s;
    16         cin>>s;
    17         sort(s.begin(),s.end());
    18         t.insert(s);
    19     }
    20     cout<<t.size();
    21     return 0;
    22 }
    View Code

    第二题:过河

      题目大意:一条河,要将东岸的n个人(n<=100000)运到西岸,只有一条船,一次最多运2个人,每个人有过河的时间花费,每一次运输的花费是船上花费最高的人的花费。问总花费时间?

      样例:输入:4 (n) 6 7 10 15(每个人的花费) 输出:42

      样例说明:{1,2,3,4}->{}  

            {3,4}-(1,2)->{1,2}  ans+=7

            {1,3,4}<-(1)-{2} ans+=6

            {1}-(3,4)->{2,3,4} ans+=15

            {1,2}<-(2)-{3,4} ans+=7

            {}-(1,2)->{1,2,3,4} ans+=7

      题解:

      考试的时候是想找规律来着,分为单数和偶数。但是只对了1组。。。正解:递推。先排序。对于每一次从东岸运走,有两种情况:一是将最快的那个人从西岸回来,和东岸的一个人走;二是将最快的那个人从西岸回来,东岸的两个人一起西岸,然后西岸的第二快的人回东岸,和最快的人一起再去西岸。分别对应了运单数个人和偶数个人的情况,并取最小花费(这就是为什么直接用人数的奇偶数来找规律的错误原因,实际应该在过程中就有运一个或两个人的情况,而非全部两个人)。

         代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define inf 100005
     5 using namespace std;
     6 int n,a[inf],f[inf];
     7 int main()
     8 {
     9     freopen("river.in","r",stdin);
    10     freopen("river.out","w",stdout);
    11     cin>>n;
    12     for (int i=1;i<=n;i++)
    13       scanf("%d",&a[i]);
    14     sort(a+1,a+1+n);
    15     f[1]=a[1];f[2]=a[2];
    16     for (int i=3;i<=n;i++)
    17     {
    18         if (f[i-1]+a[1]+a[i]<f[i-2]+a[1]+2*a[2]+a[i])
    19           f[i]=f[i-1]+a[1]+a[i];
    20         else f[i]=f[i-2]+a[1]+2*a[2]+a[i];
    21     }
    22     cout<<f[n];
    23     return 0;
    24 }
    View Code

    第三题:最短路

      题目大意:一个无向图,n个点(<=3000)m条边(<=20000),给定 k个三元数组(<=100000),(a,b,c)表示a 走到b不能往c走,但是b走到a可以往c走。在这个限制下,求出从1—n的最短路径,输出长度和过程中经过的点。输入:n,m,k   下m行为联通的边,下k行是限制数组。

      样例:输入:4 4 2            输出:  4

            1 2         1 3 2 3 4

            2 3

            3 4 

            1 3

            1 2 3

             1 3 4

      题解:最后写到这道题没有时间了。可以用BFS或SPFA。对于判断能不能走,标程的做法值得借鉴,将head数组定为二维,表示从a->b的b的下几条边是不能走的,在BFS中,用set存不能走的路,并在拓展时判断要走的路在不在集合中,BFS中,用自定义的队列数组,并且是二维,一个存当前节点,一个存当前节点的上一个节点。在记录路径时,用倒序,存从当前节点走到下一节点的路径的上一个节点。在搜索中,因为是BFS如果找到一条路,则为最优解,就可以退出了,加一条语句,可以避免TLE 两个组。

      代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<set>
     5 #include<queue>
     6 #define inf 40005 //双向边 
     7 #define maxn 3005
     8 using namespace std;
     9 int n,m,k,road[maxn][maxn],q[maxn][3];
    10 int tot,he[maxn],to[inf],ne[inf];
    11 int toto,hed[maxn][maxn],tov[inf],nex[inf];
    12 int vis[maxn][maxn];
    13 void add(int a,int b)
    14 {
    15     tot++;to[tot]=b;ne[tot]=he[a];he[a]=tot;
    16 }
    17 void add2(int a,int b,int c)
    18 {
    19     toto++;tov[toto]=c;nex[toto]=hed[a][b];hed[a][b]=toto;
    20 }
    21 void bfs()
    22 {
    23     set<int> s;
    24     int h=0,t=1;    
    25     q[1][0]=1;q[1][1]=0;
    26     vis[0][1]=1;
    27     while (h<=t)
    28     {
    29         s.clear();h++;
    30         int u=q[h][0],v=q[h][1];
    31         for (int i=hed[v][u];i;i=nex[i])
    32           s.insert(tov[i]);
    33         for (int i=he[u];i;i=ne[i])
    34           if (!vis[u][to[i]]&&s.find(to[i])==s.end())
    35           {
    36               q[++t][0]=to[i];q[t][1]=u;
    37               road[u][to[i]]=v;//record the last point
    38               vis[u][to[i]]=vis[v][u]+1;//from v -> u -> to[i]
    39               if (to[i]==n) return ;//不加 TLE 2组 
    40           }
    41     }
    42 }
    43 void print(int a,int b)
    44 {
    45     if (a) print(road[a][b],a);
    46     printf("%d ",b);
    47 }
    48 int main()
    49 {
    50     freopen("path.in","r",stdin);
    51     freopen("path.out","w",stdout);
    52     cin>>n>>m>>k;
    53     for (int i=1;i<=m;i++)
    54     {
    55         int a,b;
    56         scanf("%d%d",&a,&b);
    57         add(a,b);
    58         add(b,a);
    59     }
    60     for (int i=1;i<=k;i++)
    61     {
    62         int a,b,c;
    63         scanf("%d%d%d",&a,&b,&c);
    64         add2(a,b,c);
    65     }
    66     bfs();
    67     int min=99999999,mi;
    68     for (int i=1;i<=n;i++)
    69       if (vis[i][n]&&vis[i][n]<min) {
    70           min=vis[i][n];mi=i;
    71       }
    72     if (min==99999999) {
    73         cout<<-1;return 0;
    74     }
    75     cout<<min-1<<endl;
    76     print(mi,n);
    77     return 0;
    78 }
    View Code

      呼。。。刷题去

      

  • 相关阅读:
    C++:智能指针TR1的shared_ptr和weak_ptr使用介绍
    makefile文件
    php中格式化输出函数vprintf printf sprintf sscanf
    SQLite轻量级数据库简介(转)
    非常有用的免费UI设计工具和资源
    IAR编译duplicate definitions for IAR报错解决办法
    ATMEL推出无需授权费用的ARM处理器的定制SoC MPCFII技术
    DM9000 寄存器的定义
    php 5.3.6 连接sqlite3
    Jquery 取值 发送ajax,并修改原网页的数据
  • 原文地址:https://www.cnblogs.com/lx0319/p/5931137.html
Copyright © 2011-2022 走看看