//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 "david@beckham.com"
样例输出
<!DOCTYPE html>
< html>
< head>
< title>User David Beckham</title>
< /head>
< body>
< h1>David Beckham</h1>
< p>Email: <a href="mailto:david@beckham.com">david@beckham.com</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的通路只能由a向b传递信息。信息可以通过中转的方式进行传递,即如果a能将信息传递到b,b又能将信息传递到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;
}