ccf编程笔记(C++)

//String

string类的构造函数:

string(const char *s);    //用c字符串s初始化
string(int n,char c);     //用n个字符c初始化
此外,string类还支持默认构造函数和复制构造函数,如string s1;string s2="hello";都是正确的写法。当构造的string太长而无法表达时会抛出length_error异常 ;


string类的字符操作:
const char &operator[](int n)const;
const char &at(int n)const;
char &operator[](int n);
char &at(int n);
operator[]和at()均返回当前字符串中第n个字符的位置,但at函数提供范围检查,当越界时会抛出out_of_range异常,下标运算符[]不提供检查访问。
const char *data()const;//返回一个非null终止的c字符数组
const char *c_str()const;//返回一个以null终止的c字符串
int copy(char *s, int n, int pos = 0) const;//把当前串中以pos开始的n个字符拷贝到以s为起始位置的字符数组中,返回实际拷贝的数目


string的特性描述:
int capacity()const;    //返回当前容量(即string中不必增加内存即可存放的元素个数)
int max_size()const;    //返回string对象中可存放的最大字符串的长度
int size()const;        //返回当前字符串的大小
int length()const;       //返回当前字符串的长度
bool empty()const;        //当前字符串是否为空
void resize(int len,char c);//把字符串当前大小置为len,并用字符c填充不足的部分

string类的输入输出操作:
string类重载运算符operator>>用于输入,同样重载运算符operator<<用于输出操作。
函数getline(istream &in,string &s);用于从输入流in中读取字符串到s中,以换行符'\n'分开。

string的赋值:
string &operator=(const string &s);//把字符串s赋给当前字符串
string &assign(const char *s);//用c类型字符串s赋值
string &assign(const char *s,int n);//用c字符串s开始的n个字符赋值
string &assign(const string &s);//把字符串s赋给当前字符串
string &assign(int n,char c);//用n个字符c赋值给当前字符串
string &assign(const string &s,int start,int n);//把字符串s中从start开始的n个字符赋给当前字符串
string &assign(const_iterator first,const_itertor last);//把first和last迭代器之间的部分赋给字符串

string的连接:
string &operator+=(const string &s);//把字符串s连接到当前字符串的结尾
string &append(const char *s);            //把c类型字符串s连接到当前字符串结尾
string &append(const char *s,int n);//把c类型字符串s的前n个字符连接到当前字符串结尾
string &append(const string &s);    //同operator+=()
string &append(const string &s,int pos,int n);//把字符串s中从pos开始的n个字符连接到当前字符串的结尾
string &append(int n,char c);        //在当前字符串结尾添加n个字符c
string &append(const_iterator first,const_iterator last);//把迭代器first和last之间的部分连接到当前字符串的结尾


string的比较:
bool operator==(const string &s1,const string &s2)const;//比较两个字符串是否相等
运算符">","<",">=","<=","!="均被重载用于字符串的比较;
int compare(const string &s) const;//比较当前字符串和s的大小
int compare(int pos, int n,const string &s)const;//比较当前字符串从pos开始的n个字符组成的字符串与s的大小
int compare(int pos, int n,const string &s,int pos2,int n2)const;//比较当前字符串从pos开始的n个字符组成的字符串与s中

//pos2开始的n2个字符组成的字符串的大小
int compare(const char *s) const;
int compare(int pos, int n,const char *s) const;
int compare(int pos, int n,const char *s, int pos2) const;
compare函数在>时返回1,<时返回-1,==时返回0  


string的子串:
string substr(int pos = 0,int n = npos) const;//返回pos开始的n个字符组成的字符串

string的交换:
void swap(string &s2);    //交换当前字符串与s2的值


string类的查找函数: 
int find(char c, int pos = 0) const;//从pos开始查找字符c在当前字符串的位置
int find(const char *s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
int find(const char *s, int pos, int n) const;//从pos开始查找字符串s中前n个字符在当前串中的位置
int find(const string &s, int pos = 0) const;//从pos开始查找字符串s在当前串中的位置
//查找成功时返回所在位置,失败返回string::npos的值
int rfind(char c, int pos = npos) const;//从pos开始从后向前查找字符c在当前串中的位置
int rfind(const char *s, int pos = npos) const;
int rfind(const char *s, int pos, int n = npos) const;
int rfind(const string &s,int pos = npos) const;
//从pos开始从后向前查找字符串s中前n个字符组成的字符串在当前串中的位置,成功返回所在位置,失败时返回string::npos的值
int find_first_of(char c, int pos = 0) const;//从pos开始查找字符c第一次出现的位置
int find_first_of(const char *s, int pos = 0) const;
int find_first_of(const char *s, int pos, int n) const;
int find_first_of(const string &s,int pos = 0) const;
//从pos开始查找当前串中第一个在s的前n个字符组成的数组里的字符的位置。查找失败返回string::npos
int find_first_not_of(char c, int pos = 0) const;
int find_first_not_of(const char *s, int pos = 0) const;
int find_first_not_of(const char *s, int pos,int n) const;
int find_first_not_of(const string &s,int pos = 0) const;
//从当前串中查找第一个不在串s中的字符出现的位置,失败返回string::npos
int find_last_of(char c, int pos = npos) const;
int find_last_of(const char *s, int pos = npos) const;
int find_last_of(const char *s, int pos, int n = npos) const;
int find_last_of(const string &s,int pos = npos) const;
int find_last_not_of(char c, int pos = npos) const;
int find_last_not_of(const char *s, int pos = npos) const;
int find_last_not_of(const char *s, int pos, int n) const;
int find_last_not_of(const string &s,int pos = npos) const;
//find_last_of和find_last_not_of与find_first_of和find_first_not_of相似,只不过是从后向前查找


string类的替换函数: 
string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串


string类的插入函数: 
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c


string类的删除函数
iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串


string类的迭代器处理: 
string类提供了向前和向后遍历的迭代器iterator,迭代器提供了访问各个字符的语法,类似于指针操作,迭代器不检查范围。
用string::iterator或string::const_iterator声明迭代器变量,const_iterator不允许改变迭代的内容。常用迭代器函数有:
const_iterator begin()const;
iterator begin();                //返回string的起始位置
const_iterator end()const;
iterator end();                    //返回string的最后一个字符后面的位置
const_iterator rbegin()const;
iterator rbegin();                //返回string的最后一个字符的位置
const_iterator rend()const;
iterator rend();                    //返回string第一个字符位置的前面
rbegin和rend用于从后向前的迭代访问,通过设置迭代器string::reverse_iterator,string::const_reverse_iterator实现


字符串流处理: 
通过定义ostringstream和istringstream变量实现,#include <sstream>头文件中
例如:
    string input("hello,this is a test");
    istringstream is(input);
    string s1,s2,s3,s4;
    is>>s1>>s2>>s3>>s4;//s1="hello,this",s2="is",s3="a",s4="test"
    ostringstream os;
    os<<s1<<s2<<s3<<s4;
    cout<<os.str();

 

 

试题名称:

模板生成系统

 

问题描述

  成成最近在搭建一个网站,其中一些页面的部分内容来自数据库中不同的数据记录,但是页面的基本结构是相同的。例如,对于展示用户信息的页面,当用户为 Tom 时,网页的源代码是


  而当用户为 Jerry 时,网页的源代码是


  这样的例子在包含动态内容的网站中还有很多。为了简化生成网页的工作,成成觉得他需要引入一套模板生成系统。
  模板是包含特殊标记的文本。成成用到的模板只包含一种特殊标记,格式为 {{ VAR }},其中 VAR 是一个变量。该标记在模板生成时会被变量 VAR 的值所替代。例如,如果变量 name = "Tom",则 {{ name }} 会生成 Tom。具体的规则如下:
·变量名由大小写字母、数字和下划线 (_) 构成,且第一个字符不是数字,长度不超过 16 个字符。
·变量名是大小写敏感的,Name 和 name 是两个不同的变量。
·变量的值是字符串。
·如果标记中的变量没有定义,则生成空串,相当于把标记从模板中删除。
·模板不递归生成。也就是说,如果变量的值中包含形如 {{ VAR }} 的内容,不再做进一步的替换。

输入格式

  输入的第一行包含两个整数 m, n,分别表示模板的行数和模板生成时给出的变量个数。
  接下来 m 行,每行是一个字符串,表示模板。
  接下来 n 行,每行表示一个变量和它的值,中间用一个空格分隔。值是字符串,用双引号 (") 括起来,内容可包含除双引号以外的任意可打印 ASCII 字符(ASCII 码范围 32, 33, 35-126)。

输出格式

  输出包含若干行,表示模板生成的结果。

样例输入

11 2
< !DOCTYPE html>
< html>
< head>
< title>User {{ name }}</title>
< /head>
< body>
< h1>{{ name }}</h1>
< p>Email: <a href="mailto:{{ email }}">{{ email }}</a></p>
< p>Address: {{ address }}</p>
< /body>
< /html>
name "David Beckham"
email "[email protected]"

样例输出

<!DOCTYPE html>
< html>
< head>
< title>User David Beckham</title>
< /head>
< body>
< h1>David Beckham</h1>
< p>Email: <a href="mailto:[email protected]">[email protected]</a></p>
< p>Address: </p>
< /body>
< /html>

评测用例规模与约定

0 ≤ m ≤ 100
0 ≤ n ≤ 100
  输入的模板每行长度不超过 80 个字符(不包含换行符)。
  输入保证模板中所有以 {{ 开始的子串都是合法的标记,开始是两个左大括号和一个空格,然后是变量名,结尾是一个空格和两个右大括号。
  输入中所有变量的值字符串长度不超过 100 个字符(不包括双引号)。
  保证输入的所有变量的名字各不相同。

 

#include "map"

#include "iostream"

#include "string"

using namespace std;

int main() {

    int lineNum, varNum;

    cin >> lineNum >> varNum;

    string inputStr, outputStr, tempStr;

    map<string, string> varDict;

 

    getchar(); // consume next new line character

    for(int i=0; i<lineNum; i++) {

      getline(cin, tempStr);

      inputStr += tempStr + '\n';

    }

     string varKey, varValue;

    for(int i=0; i<varNum; i++) {

      cin >> varKey;

      getline(cin, tempStr);

      int startQuote = tempStr.find("\"");

      int endQuote = tempStr.rfind("\"");

      varValue = tempStr.substr(startQuote+1, endQuote-startQuote-1);

      //cout << value;

      varDict[varKey] = varValue;

    }

    int startPos, endPos; // startPos->{{ endPos->}}

    int startPoint = 0; // start position for string.find

     while(true) {

      startPos = inputStr.find("{{", startPoint);

      endPos = inputStr.find("}}", startPos);

      if(startPos<0 || endPos <0) break;

      varKey = inputStr.substr(startPos+3, endPos-startPos-4);

      varValue = "";

      if(varDict.find(varKey) != varDict.end()) varValue = varDict[varKey];

      outputStr += inputStr.substr(startPoint, startPos-startPoint) + varValue;

      startPoint = endPos + 2;

    }

    outputStr += inputStr.substr(startPoint, inputStr.length());

 

    cout << outputStr;

}

 

 

//String.h

 

void *memcpy(void *dest, const void *src, size_t n);

从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中.

void *memmove( void* dest, const void* src,size_t count);

由src所指内存区域复制count个字节到dest所指内存区域。
memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。

void *memset(void *s, int ch, size_t n);

将s中前n个字节(typedef unsigned int size_t)用ch替换并返回s。
memset作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法.

int memcmp(const void *buf1, const void *buf2, unsigned int count);

比较内存区域buf1和buf2的前count个字节。
当buf1<buf2时,返回值<0
当buf1=buf2时,返回值=0
当buf1>buf2时,返回值>0

extern char *strcpy(char* dest, const char *src);

把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间.src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。

char * strncpy(char *dest, char *src,size_t num);

复制src中的内容(字符,数字、汉字....)到dest,复制多少由num的值决定,返回指向dest的指针。如果遇到null字符('\0'),且还没有到num个字符时,就用(num - n)(n是遇到null字符前已经有的非null字符个数)个null字符附加到destination。

extern char *strcat(char *dest,char *src);

把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。

extern char *strncat(char *dest,char *src,int n);

把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。

extern int strcmp(const char *s1,const char * s2);

比较字符串s1和s2。
当s1<s2时,返回值<0
当s1==s2时,返回值=0
当s1>s2时,返回值>0
即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。

int strncmp(char *str1, char *str2, int maxlen);

此函数功能即比较字符串str1和str2的前maxlen个字符。

如果前maxlen字节完全相等,返回值就=0;

在前maxlen字节比较过程中,如果出现str1[n]与str2[n]不等,则返回(str1[n]-str2[n])。

 

int strcasecmp (const char *s1, const char *s2);

strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异。

若参数s1和s2字符串相等则返回0。

s1大于s2则返回大于0 的值。

s1 小于s2 则返回小于0的值。

 

int strncasecmp(const char *s1, const char *s2, size_t n)

strncasecmp()用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异,

若参数s1和s2字符串相同则返回0 

s1若大于s2则返回大于0的值

s1若小于s2则返回小于0的值.

 

extern char *strchr(const char *s,char c);

查找字符串s中首次出现字符c的位置,返回首次出现c的位置的指针,如果s中不存在c则返回NULL。

extern unsigned int strlen(char *s);

计算字符串s的(unsigned int型)长度,不包括'\0'在内.返回s的长度,不包括结束符NULL。

 

 

 

 

//Vector

vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector是一个容器,它能够存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,可以动态改变大小。
例如:

1

2

3

4

// c语言风格

int myHouse[100] ;

// 采用vector

vector<int> vecMyHouse(100);

当如上定义后,vecMyHouse就可以存放100个int型的数据了。

1. 它可以像普通数组一样访问
例如:

1

vecMyHouse[50] = 1024;

2. 你可以顺序地向容器中填充数据
例如:

1

2

3

4

5

int i =0 ;

for( ;i< 25; i++ )

{

vecMyHouse.push_back(1);

}

3. 它还可以动态地改变它的大小,通过下面这条语句实现
将容器的大小改为400,这样容器中就可以容纳400个int型数据了
例如:

1

vecMyHouse.resize(400);

4. 你也可以在容器中装入自定义的数据类型
例如:

1

2

3

4

5

6

// 自定义一个class

class Cmyclass

{

};

// 定义一个存放class的容器

vector<Cmyclass> vecMyHouse;

5. 你可以在定义容器时为它赋初值

1

2

// 定义一个容纳100个int型数据的容器,初值赋为0

vector<int> vecMyHouse(100,0);

6. 你可以把一个容器的对象赋值给另外一个容器
例如:

1

2

3

4

5

// 定义一个容纳100个int型数据的容器,初值赋为0

vector<int> vecMyHouse(100,0);

// 定义一个新的容器,内容与上述容器一样

vector<int> myVec ;

myVec = vecMyHouse;

二、 以上是vector容器的简单介绍,下面将详细介绍它的其他功能:

1. 为了使用vector,必须在你的头文件中包含下面的代码:

1

#include <vector>

2. vector属于std命名域的,因此需要通过命名限定,可以在文件开头加上

1

using std::vector;

或者

1

using namespace std;

或者直接在使用vector的代码前加前缀
例如:

1

std::vector<int> myHouse;

3. vector提供如下函数或操作:
下面列举了部分常用的功能

1

2

// 定义一个vector

std::vector<int> c;

可以使用的功能:
c.clear()         移除容器中所有数据。
c.empty()         判断容器是否为空。
c.erase(pos)        删除pos位置的数据
c.erase(beg,end) 删除[beg,end)区间的数据
c.front()         传回第一个数据。
c.insert(pos,elem)  在pos位置插入一个elem拷贝
c.pop_back()     删除最后一个数据。
c.push_back(elem) 在尾部加入一个数据。
c.resize(num)     重新设置该容器的大小
c.size()         回容器中实际数据的个数。
c.begin()           返回指向容器第一个元素的迭代器
c.end()             返回指向容器最后一个元素的迭代器

三、下面描述一下什么是迭代器

迭代器相当于指针,例如:

1

2

3

4

5

// 对于变量而言,使用指针指向对应的变量

// 以后就可以使用 * 加指针来操作该变量了

int a = 10;

int *p;

p = &a;

使用指针操作该变量
例如: *p = 11; // 操作后a变为 11
对于容器,使用迭代器操作容器中对应位置的值
当迭代器指向了容器中的某位置,则可以使用 * 加迭代器操作该位置了

1

2

3

4

5

6

7

// 定义一个vector

std::vector<int> myVec;

//添加10个元素

for(int j =0 ; j<10 ; j++)

{

myVec.push_back(j);

}

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

// 定义一个迭代器

std::vector<int>::iterator p;

// 指向容器的首个元素

p = myVec.begin();

// 移动到下一个元素

p ++;

// 修改该元素赋值

*p = 20 ; //< 则myVec容器中的第二个值被修改为了20

// 循环扫描迭代器,改变所有的值

p = myVec.begin();

for( ; p!= myVec.end(); p++ )

{

*p = 50;

}

以上简单讲述了vector的用法,仅供入门之用,下面以实例形式继续加以说明。

1.vector 的数据的存入和输出:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include<stdio.h>

#include<vector>

#include <iostream>

using namespace std;

void main()

{

 int i = 0;

  vector<int> v;

  for( i = 0; i < 10; i++ )

 {

      v.push_back( i );//把元素一个一个存入到vector中

 }

  //对存入的数据清空

 for( i = 0; i < v.size(); i++ )//v.size() 表示vector存入元素的个数

 {

     cout << v[ i ] << " "; //把每个元素显示出来

 }

 cont << endl;

}

注:你也可以用v.begin()和v.end() 来得到vector开始的和结束的元素地址的指针位置。

你也可以这样做:

1

2

3

4

5

vector<int>::iterator iter;

for( iter = v.begin(); iter != v.end(); iter++ )

{

  cout << *iter << endl;

}

2. 对于二维vector的定义。
1)定义一个10个vector元素,并对每个vector符值1-10。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include<stdio.h>

#include<vector>

#include <iostream>

using namespace std;

void main()

{

int i = 0, j = 0;

//定义一个二维的动态数组,有10行,每一行是一个用一个vector存储这一行的数据。

//所以每一行的长度是可以变化的。之所以用到vector<int>(0)是对vector初始化,否则不能对vector存入元素。

vector< vector<int> > Array( 10, vector<int>(0) );

for( j = 0; j < 10; j++ )

{

 for ( i = 0; i < 9; i++ )

 {

  Array[ j ].push_back( i );

 }

}

for( j = 0; j < 10; j++ )

{

 for( i = 0; i < Array[ j ].size(); i++ )

 {

  cout << Array[ j ][ i ] << " ";

 }

 cout<< endl;

}

}

2)定义一个行列都是变化的数组。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include<stdio.h>

#include<vector>

#include <iostream>

using namespace std;

void main()

{

int i = 0, j = 0;

vector< vector<int> > Array;

vector< int > line;

for( j = 0; j < 10; j++ )

{

 Array.push_back( line );//要对每一个vector初始化,否则不能存入元素。

 for ( i = 0; i < 9; i++ )

 {

  Array[ j ].push_back( i );

 }

}

for( j = 0; j < 10; j++ )

{

 for( i = 0; i < Array[ j ].size(); i++ )

 {

  cout << Array[ j ][ i ] << " ";

 }

 cout<< endl;

}

}

使用 vettor erase 指定元素,示例如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

#include "iostream"

#include "vector"

using namespace std;

int main()

{

  vector<int> arr;

  arr.push_back(6);

  arr.push_back(8);

  arr.push_back(3);

  arr.push_back(8);

  for(vector<int>::iterator it=arr.begin(); it!=arr.end(); )

  {

    if(* it == 8)

    {

      it = arr.erase(it);

    }

    else

    {

      ++it;

    }

  }

  cout << "After remove 8:\n";

  for(vector<int>::iterator it = arr.begin(); it < arr.end(); ++it)

  {

    cout << * it << " ";

  }

  cout << endl;

}

 

 

 

//map

1. map最基本的构造函数;
   map<string , int >mapstring;         map<int ,string >mapint;
   map<sring, char>mapstring;         map< char ,string>mapchar;
   map<char ,int>mapchar;            map<int ,char >mapint;
2. map添加数据;
   map<int ,string> maplive;  
   1.maplive.insert(pair<int,string>(102,"aclive"));
   2.maplive.insert(map<int,string>::value_type(321,"hai"));
   3, maplive[112]="April";//map中最简单最常用的插入添加!
3,map中元素的查找:
   find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。        
   map<int ,string >::iterator l_it;; 
   l_it=maplive.find(112);
   if(l_it==maplive.end())
                cout<<"we do not find 112"<<endl;
   else cout<<"wo find 112"<<endl;
4,map中元素的删除:
   如果删除112;
   map<int ,string >::iterator l_it;;
   l_it=maplive.find(112);
   if(l_it==maplive.end())
        cout<<"we do not find 112"<<endl;
   else  maplive.erase(l_it);  //delete 112;
5,map中 swap的用法:
  Map中的swap不是一个容器中的元素交换,而是两个容器交换;
  For example:
  #include <map>
  #include <iostream>
  using namespace std;
  int main( )
  {
      map <int, int> m1, m2, m3;
      map <int, int>::iterator m1_Iter;
      m1.insert ( pair <int, int>  ( 1, 10 ) );
      m1.insert ( pair <int, int>  ( 2, 20 ) );
      m1.insert ( pair <int, int>  ( 3, 30 ) );
      m2.insert ( pair <int, int>  ( 10, 100 ) );
      m2.insert ( pair <int, int>  ( 20, 200 ) );
      m3.insert ( pair <int, int>  ( 30, 300 ) );
   cout << "The original map m1 is:";
   for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
      cout << " " << m1_Iter->second;
      cout   << "." << endl;
   // This is the member function version of swap
   //m2 is said to be the argument map; m1 the target map
   m1.swap( m2 );
   cout << "After swapping with m2, map m1 is:";
   for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
      cout << " " << m1_Iter -> second;
      cout  << "." << endl;
   cout << "After swapping with m2, map m2 is:";
   for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )
      cout << " " << m1_Iter -> second;
      cout  << "." << endl;
   // This is the specialized template version of swap
   swap( m1, m3 );
   cout << "After swapping with m3, map m1 is:";
   for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
      cout << " " << m1_Iter -> second;
      cout   << "." << endl;
}
6.map的sort问题:
  Map中的元素是自动按key升序排序,所以不能对map用sort函数:
  For example:
  #include <map>
  #include <iostream>
  using namespace std;
 int main( )
 {
   map <int, int> m1;
   map <int, int>::iterator m1_Iter;
   m1.insert ( pair <int, int>  ( 1, 20 ) );
   m1.insert ( pair <int, int>  ( 4, 40 ) );
   m1.insert ( pair <int, int>  ( 3, 60 ) );
   m1.insert ( pair <int, int>  ( 2, 50 ) );
   m1.insert ( pair <int, int>  ( 6, 40 ) );
   m1.insert ( pair <int, int>  ( 7, 30 ) );
   cout << "The original map m1 is:"<<endl;
   for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
      cout <<  m1_Iter->first<<" "<<m1_Iter->second<<endl;
  
}
  The original map m1 is:
  1 20
  2 50
  3 60
  4 40
  6 40
  7 30
  请按任意键继续. . .
7,   map的基本操作函数:
      C++ Maps是一种关联式容器,包含“关键字/值”对
      begin()          返回指向map头部的迭代器
      clear()         删除所有元素
      count()          返回指定元素出现的次数
      empty()          如果map为空则返回true
      end()            返回指向map末尾的迭代器
      equal_range()    返回特殊条目的迭代器对
      erase()          删除一个元素
      find()           查找一个元素
      get_allocator()  返回map的配置器
      insert()         插入元素
      key_comp()       返回比较元素key的函数
      lower_bound()    返回键值>=给定元素的第一个位置
      max_size()       返回可以容纳的最大元素个数
      rbegin()         返回一个指向map尾部的逆向迭代器
      rend()           返回一个指向map头部的逆向迭代器
      size()           返回map中元素的个数
      swap()            交换两个map
      upper_bound()     返回键值>给定元素的第一个位置
      value_comp()      返回比较元素value的函数

 

 

 

 

 

 

 

 

//dfs

 

试题名称:

网络延时

 

样例输入

4 2
1 1 3
2 1

样例输出

4

样例说明

样例的网络连接模式如下,其中圆圈表示交换机,方框表示电脑:



  其中电脑1与交换机4之间的消息传递花费的时间最长,为4个单位时间。

 

//找一棵树中距离最长的两个点之间的距离:

//思想:首先任取一个点,从该点出发,找到距离该初始点最远的一个点v,

//再从v出发,同样的方法找出从v开始的最长路径的点x,则v到x即为所求最长路径

#include <bits/stdc++.h>

using namespace std;

const int maxn=20005; //因为n m 相加需要20000

int vis[maxn];

int maxCost,number;

 

vector <int> G[maxn];

void init()

{

    for(int i=0; i<maxn; i++)

        G[i].clear();

}

void dfs(int u,int cost)

{

    vis[u]=1; //是否通过

    if(maxCost<cost)

    {

        maxCost=cost; //记录最长路径距离 因为有回溯所以需要全局变量

        number=u;  //记录最长距离的最后一个点

    }

    for(int i=0; i<G[u].size(); i++) //对U的每一个邻接点遍历

    {

        if(!vis[G[u][i]])  //若该邻接点未标记,则距离加1,继续递归调用

            dfs(G[u][i],cost+1);

    }

}

int main()

{

    int n,m,x,i;

    cin>>n>>m;

    init();

    for(i=2; i<=n+m; i++)

    {

        cin>>x;

        G[i].push_back(x);//第i个的前一个  机器顺延交换机顺序

        G[x].push_back(i);//无向图

    }

    maxCost=-1;  //每次调用dfs函数时,首先要对最大值初始化为-1,且vis初始化为0

    memset(vis,0,sizeof(vis));//访问变量初始化

    dfs(1,0);

    maxCost=-1;

    memset(vis,0,sizeof(vis));

    dfs(number,0);

    cout<<maxCost<<endl;

    return 0;

}

 

试题名称:

通信网络

问题描述

  某国的军队由N个部门组成,为了提高安全性,部门之间建立了M条通路,每条通路只能单向传递信息,即一条从部门a到部门b的通路只能由ab传递信息。信息可以通过中转的方式进行传递,即如果a能将信息传递到bb又能将信息传递到c,则a能将信息传递到c。一条信息可能通过多次中转最终到达目的地。
  由于保密工作做得很好,并不是所有部门之间都互相知道彼此的存在。只有当两个部门之间可以直接或间接传递信息时,他们才彼此知道对方的存在。部门之间不会把自己知道哪些部门告诉其他部门。



  上图中给了一个4个部门的例子,图中的单向边表示通路。部门1可以将消息发送给所有部门,部门4可以接收所有部门的消息,所以部门1和部门4知道所有其他部门的存在。部门2和部门3之间没有任何方式可以发送消息,所以部门2和部门3互相不知道彼此的存在。
  现在请问,有多少个部门知道所有N个部门的存在。或者说,有多少个部门所知道的部门数量(包括自己)正好是N

输入格式

  输入的第一行包含两个整数N, M,分别表示部门的数量和单向通路的数量。所有部门从1到N标号。
  接下来M行,每行两个整数a, b,表示部门a到部门b有一条单向通路。

输出格式

  输出一行,包含一个整数,表示答案。

样例输入

4 4
1 2
1 3
2 4
3 4

样例输出

2

样例说明

  部门1和部门4知道所有其他部门的存在。

评测用例规模与约定

  对于30%的评测用例,1 ≤ N ≤ 10,1 ≤ M ≤ 20;
  对于60%的评测用例,1 ≤ N ≤ 100,1 ≤ M ≤ 1000;
  对于100%的评测用例,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000。

 

#include <iostream>

#include<vector>

using namespace std;

vector<int> v[1024];

int isconnect[1024][1024];

 

void dfsSolve(int u,int visit[],int cur)

{

    visit[u]=1;

    isconnect[u][cur]=isconnect[cur][u]=1;

    for(size_t i=0;i<v[u].size();++i)

    {

        if(visit[v[u][i]]==0)

            dfsSolve(v[u][i],visit,cur);

    }

}

int main()

{

    int n,m,total=0;

    cin>>n>>m;

    for(int i=0;i<m;++i)

    {

        int s,e;

        cin>>s>>e;

        v[s].push_back(e);

    }

    for(int i=1;i<=n;++i)

    {

        int visit[1024]={0};

        dfsSolve(i,visit,i);

    }

    for(int i=1;i<=n;++i)

    {

        int j;

        for(j=1;j<=n;++j)

            if(isconnect[i][j]==0)break;

        if(j==n+1)

++total;

    }

    cout<<total;

    return 0;

}

 

 

 

 

 

 

 

 

//kruskal

 

#include<iostream>

#include <cstdio>

#include <string.h>

#include<algorithm>  

using namespace std;  

const int MAXN=505;//最大点数  

const int MAXM=250005;//最大边数  

int F[MAXN];//并查集使用  

struct Edge  

{  

    int u,v,w;  

}edge[MAXM];//储存边的信息,包括起点/终点/权值  

int tol;//边数,加边前赋值为0  

void addedge(int u,int v,int w)  

{  

    edge[tol].u=u;  

    edge[tol].v=v;  

    edge[tol++].w=w;  

}

bool cmp(Edge a,Edge b)//排序函数,边按照权值从小到大排序  

{  

    return a.w<b.w;  

}  

int Find(int x)  

{  

    if(F[x]==-1)  

        return x;  

    else  

        return F[x]=Find(F[x]);  

}  

int Kruskal(int n)//传入点数,返回最小生成树的权值,如果不连通返回-1  

{  

    memset(F,-1,sizeof(F));  

    sort(edge,edge+tol,cmp);  

    int cnt=0,ans=0;//计算加入的边数  

    for(int i=0;i<tol;i++)  

    {  

        int u=edge[i].u;  

        int v=edge[i].v;  

        int w=edge[i].w;  

        int t1=Find(u);  

        int t2=Find(v);  

        if(t1!=t2)

        {  

            ans+=w;  

            F[t1]=t2;  

            cnt++;  

        }

        if(cnt==n-1)

            break;  

    }

    if(cnt<n-1)

        return -1;//不连通  

    else  

        return ans;  

}

int main()

{

int n,m,a,b,c;

scanf("%d%d",&n,&m);

tol=m;           ///tol为边数

for(int i=0;i<m;i++){

scanf("%d%d%d",&a ,&b,&c);

edge[i].u=a;

edge[i].v=b;

edge[i].w=c;

}

cout<<Kruskal(n)<<endl;

return 0 ;

}

 

 

试题名称:

地铁修建

 

问题描述

A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n号枢纽间修建一条地铁。
  地铁由很多段隧道组成,每段隧道连接两个交通枢纽。经过勘探,有m段隧道作为候选,两个交通枢纽之间最多只有一条候选的隧道,没有隧道两端连接着同一个交通枢纽。
  现在有n家隧道施工的公司,每段候选的隧道只能由一个公司施工,每家公司施工需要的天数一致。而每家公司最多只能修建一条候选隧道。所有公司同时开始施工。
  作为项目负责人,你获得了候选隧道的信息,现在你可以按自己的想法选择一部分隧道进行施工,请问修建整条地铁最少需要多少天。

输入格式

  输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量。
  第2行到第m+1行,每行包含三个整数a, b, c,表示枢纽a和枢纽b之间可以修建一条隧道,需要的时间为c天。

输出格式

  输出一个整数,修建整条地铁线路最少需要的天数。

样例输入

6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6

样例输出

6

 

#include<iostream>

#include<vector>

#include<algorithm>

using namespace std;

#define maxx 100010

struct node{

int x,y,z;

}n1;

int p[maxx];

int n,m;

vector<struct node>vec;

bool cmp(struct node n2,struct node n3)

{

return n2.z < n3.z;

}

int find(int x)

{

if(p[x] == x)

{

return x;

}else{

int y=find(p[x]);

p[x] = y;

return y;

}

}

void union_p(int x,int y)

{

if(x==y)

{

return ;

}

p[x] = y;

}

int main()

{

int x,y,z;

cin >> n >> m;

for(int i=0;i<m;i++)

{

cin >> x >> y >> z;

n1.x=x,n1.y=y,n1.z=z;

vec.push_back(n1);

}

sort(vec.begin(),vec.end(),cmp);

for(int i=1;i<=n;i++)

{

p[i]=i;

}

int i=0;

while(i<m)

{

x=vec[i].x,y=vec[i].y,z=vec[i].z;

int xf = find(x);

int yf = find(y);

union_p(xf,yf);

if(find(1)==find(n))

{

break;

}

i++;

}

cout << z << endl;

return 0;

}

 

 

 

 

 

 

 

//tarjan

//有向图强连通分量 -- tarjin算法

#include<iostream>

#include<stack>

#include<vector>

#include<cstring>

#include<algorithm>

#include<fstream>

using namespace std;

#define M 100005//题目中可能最大点数

int STACK[M],top=0;//Tarjan算法中的栈

bool InStack[M];//检查是否在栈中

int DFN[M];//深度优先搜索访问次序

int Low[M];//能追溯到的最早的次序

int ComponentNumber=0;//有向图强连通分量的个数

int Index=0;//索引号

vector<int> Edge[M];//邻接表表示

vector<int> Component[M];//获得强连通分量结果

int InComponent[M];//记录每个点在第几号强连通分量里

int ComponentDegree[M];//记录每个强连通分量的度

 

void Tarjan(int i){

int j;

DFN[i]=Low[i]=Index++;

InStack[i]=true;

STACK[++top]=i;

for(int e=0;e<Edge[i].size();e++){

j=Edge[i][e];

if(DFN[j]==-1){

Tarjan(j);

Low[i]=min(Low[i],Low[j]);

}

else if(InStack[j])

Low[i]=min(Low[i],DFN[j]);

}

if(DFN[i]==Low[i]){

ComponentNumber++;

do{

j=STACK[top--];

InStack[j]=false;

Component[ComponentNumber].push_back(j);

InComponent[j]=ComponentNumber;

}

while(j!=i);

}

}

 

试题名称:

高速公路

 

问题描述

  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。
  现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。
  国王想知道,在大臣们给他的计划中,有多少个便利城市对。

输入格式

  输入的第一行包含两个整数n, m,分别表示城市和单向高速公路的数量。
  接下来m行,每行两个整数a, b,表示城市a有一条单向的高速公路连向城市b

输出格式

  输出一行,包含一个整数,表示便利城市对的数量。

样例输入

5 5
1 2
2 3
3 4
4 2
3 5

样例输出

3

样例说明


  城市间的连接如图所示。有3个便利城市对,它们分别是(2, 3), (2, 4), (3, 4),请注意(2, 3)和(3, 2)看成同一个便利城市对。

 

//有向图强连通分量 -- tarjin算法

#include<iostream>

#include<stack>

#include<vector>

#include<cstring>

#include<algorithm>

#include<fstream>

#define N 100005

 

using namespace std;

 

int n, m;               //城市和单向高速公路的数量

int DFN[N];             //节点u搜索的次序编号(时间戳)

int Low[N];             //u或u的子树能够追溯到的最早的栈中节点的次序号

bool vis[N];            //是否已访问

bool inS[N];            //是否在栈中

int time = 0;           //时间戳  

vector <int> G[N];      //邻接表

stack <int> s;          //DFS栈

int result = 0;         //最终结果:所有强连通分量中结点对的个数

int componentNum=0;     //强连通分量的个数

 

void tarjan( int u ){

    DFN[u] = Low[u] = ++time;       //时间戳从1开始

    s.push(u);                      //结点u入栈

    inS[u] = 1;                     //在栈中

    vis[u] = 1;                     //已访问

    int v;

    for( int i = 0; i < G[u].size(); i++ ){ //访问邻接表

        v = G[u][i];

        if( vis[v] == 0 ){

            tarjan( v );

            Low[u] = min( Low[u], Low[v] );

        }

        else if( inS[v] == 1 ){

            Low[u] = min( Low[u], DFN[v] );

        }

    }   

    int count = 0;          //强连通分量中结点个数

    if( DFN[u] == Low[u] ){

     componentNum++;

        do{

            v = s.top();

            inS[v] = 0;

            s.pop();

            count++;

        }while( u != v );

 

        if( count > 0 ){

            result += count * ( count-1 ) / 2;

        }

    }

 

}

 

int main(){

    int a, b;

 

    memset( DFN, 0, sizeof(DFN) );

    memset( Low, 0, sizeof(Low) );

    memset( G, 0, sizeof(G) );

    memset( inS, 0, sizeof(inS) );

    memset( vis, 0, sizeof(vis) );

 

 

    cin >> n >> m;

 

    for( int i = 0; i < m; i++ ){

        cin >> a >> b;

        G[a].push_back(b) ;

    }

 

    for( int i = 1; i <= n; i++ ){

        if( vis[i] == 0 ){

            tarjan( i );

        }

    }

 

    cout << result<<endl;

//cout<<componentNum<<endl;

 

    return 0;

}

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/muhehhh/article/details/81279414