1043. Is It a Binary Search Tree (25)

1.题目给出一个前序遍历的数组,要求判断是否是BST或者是镜像的BST,如果是,则输出它的层次遍历。

2.写两个函数,分别用来建立正常的BST:dfs和镜像BST:dfsMirror。这样就不用在检查的时候进行判断。

3.如果使用dfs不能建立BST,那么使用dfsMirror进行建立,两者都不能建立,则输出NO。

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node’s key.
  • Both the left and right subtrees must also be binary search trees.

If we swap the left and right subtrees of every node, then the resulting tree is called the Mirror Image of a BST.

Now given a sequence of integer keys, you are supposed to tell if it is the preorder traversal sequence of a BST or the mirror image of a BST.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (<=1000). Then N integer keys are given in the next line. All the numbers in a line are separated by a space.

Output Specification:

For each test case, first print in a line “YES” if the sequence is the preorder traversal sequence of a BST or the mirror image of a BST, or “NO” if not. Then if the answer is “YES”, print in the next line the postorder traversal sequence of that tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.

Sample Input 1:

7
8 6 5 7 10 8 11

Sample Output 1:

YES
5 7 6 8 11 10 8

Sample Input 2:

7
8 10 11 8 6 7 5

Sample Output 2:

YES
11 8 10 7 5 6 8

Sample Input 3:

7
8 6 8 5 10 9 11

Sample Output 3:

NO

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
struct TreeNode{
	int val;
	TreeNode *l, *r;
	TreeNode(int x) :val(x), l(NULL), r(NULL){};
	TreeNode() :val(-1), l(NULL), r(NULL){};
};
TreeNode*dfs(vector<int>&node, int l, int r, bool&buildSuccess)
{//建立正常的BST
	if (l>r) return NULL;
	else if (l == r)
	{
		return new TreeNode(node[l]);
	}
	else
	{
		TreeNode* root = new TreeNode(node[l]);
		int i = l + 1;
		while (i <= r&&node[i]<root->val)
		{
			i++;
		}
		int j = i;
		while (j <= r&&node[j] >= root->val)
		{
			j++;
		}
		if (i != r + 1 && j != r + 1)
		{//如果i没有达到最终点且j也没有到达最终点,证明数组里面有部分点不满足要求,所以不能构建
			buildSuccess = false;
			return NULL;
		}
		root->l = dfs(node, l + 1, i - 1, buildSuccess);
		root->r = dfs(node, i, r, buildSuccess);
		return root;
	}
}


TreeNode*dfsMirror(vector<int>&node, int l, int r, bool&buildSuccess)
{//基本同上
	if (l>r) return NULL;
	else if (l == r)
	{
		return new TreeNode(node[l]);
	}
	else
	{
		TreeNode* root = new TreeNode(node[l]);
		int i = l + 1;
		while (i <= r&&node[i] >= root->val)
		{
			i++;
		}
		int j = i;
		while (j <= r&&node[j]<root->val)
		{
			j++;
		}
		if (i != r + 1 && j != r + 1)
		{
			buildSuccess = false;
			return NULL;
		}
		root->l = dfsMirror(node, l + 1, i - 1, buildSuccess);
		root->r = dfsMirror(node, i, r, buildSuccess);
		return root;
	}
}

void postOrderDFS(TreeNode*root, vector<int>&postOrder)
{
	if (root != NULL)
	{
		postOrderDFS(root->l, postOrder);
		postOrderDFS(root->r, postOrder);
		postOrder.push_back(root->val);
	}
}
/*
7 8 6 5 7 10 8 11

7 8 10 11 8 6 7 5

7 8 6 8 5 10 9 11
*/
int main(void)
{

	int nodeSum;
	cin >> nodeSum;
	vector<int> node(nodeSum);
	for (int i = 0; i<nodeSum; i++)
	{
		scanf("%d", &node[i]);
	}
	bool buildSuccess = true;
	TreeNode*tree = dfs(node, 0, (int)(node.size() - 1), buildSuccess);
	if (!buildSuccess)
	{
		buildSuccess = true;
		tree = dfsMirror(node, 0, (int)(node.size() - 1), buildSuccess);
	}
	if (buildSuccess)
	{
		cout << "YES" << endl;
		vector<int> postOrder(0);
		postOrderDFS(tree, postOrder);
		for (int i = 0; i<postOrder.size(); i++)
		{
			cout << postOrder[i];
			if (i != postOrder.size() - 1)
				cout << " ";
		}
		cout << endl;
	}
	else
		cout << "NO" << endl;
	return 0;
}

1042. Shuffling Machine (20)

1.建立一个shuffling数组,把j号卡放在shuffling[j]的位置。

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techniques are seen as weak, and in order to avoid “inside jobs” where employees collaborate with gamblers by performing inadequate shuffles, many casinos employ automatic shuffling machines. Your task is to simulate a shuffling machine.

The machine shuffles a deck of 54 cards according to a given random order and repeats for a given number of times. It is assumed that the initial status of a card deck is in the following order:

S1, S2, …, S13, H1, H2, …, H13, C1, C2, …, C13, D1, D2, …, D13, J1, J2

where “S” stands for “Spade”, “H” for “Heart”, “C” for “Club”, “D” for “Diamond”, and “J” for “Joker”. A given order is a permutation of distinct integers in [1, 54]. If the number at the i-th position is j, it means to move the card from position i to position j. For example, suppose we only have 5 cards: S3, H5, C1, D13 and J2. Given a shuffling order {4, 2, 5, 3, 1}, the result will be: J2, H5, D13, S3, C1. If we are to repeat the shuffling again, the result will be: C1, H5, S3, J2, D13.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer K (<= 20) which is the number of repeat times. Then the next line contains the given order. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the shuffling results in one line. All the cards are separated by a space, and there must be no extra space at the end of the line.

Sample Input:

2
36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47

Sample Output:

S7 C11 C10 C12 S1 H7 H8 H9 D8 D9 S11 S12 S13 D10 D11 D12 S3 S4 S6 S10 H1 H2 C13 D2 D3 D4 H6 H3 D13 J1 J2 C1 C2 C3 C4 D1 S5 H5 H11 H12 C6 C7 C8 C9 S2 S8 S9 H10 D5 D6 D7 H4 H13 C5

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
/*
2
36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47
3
36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47

1
14 15 16 17 18 19 20 21 22 23 24 25 26 1 2 3 4 5 6 7 8 9 10 11 12 13 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
*/
string int2Card(int a)
{
	string ans = "";
	int pic = a / 13;
	if (pic == 0)ans = "S";
	else if (pic == 1) ans = "H";
	else if (pic == 2) ans = "C";
	else if (pic == 3) ans = "D";
	else if (pic == 4) ans = "J";
	if (a % 13 >= 9)
	{
		ans += '1';
		char c = (a % 13 - 9) + '0';
		ans += c;
	}
	else
	{
		char c = a % 13 + '1';
		ans += c;
	}
	return ans;
}
int main(void)
{
	//for (int i = 0; i < 54; i++)
	//{
	//	cout << ",\"" << int2Card(i)<<"\"";
	//}
	int repeatTime;
	cin >> repeatTime;
	vector<int> shuffling(54);
	vector<string> original = { "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "S12", "S13", "H1", "H2",
		"H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "H11", "H12", "H13", "C1", "C2", "C3", "C4", "C5","C6","C7","C8","C9","C10","C11","C12","C13","D1","D2","D3","D4","D5","D6","D7","D8","D9","D10","D11","D12","D13","J1","J2"};
	vector<string> num(54);
	for (int i = 0; i<54; i++)
	{
		cin >> shuffling[i];
		shuffling[i]--;
		num[i] = i;// initial the shuffling vector
	}


	for (int i = 0; i<repeatTime; i++)
	{
		for (int j = 0; j<54; j++)
		{//把j号卡放在shuffling[j]的位置
			num[shuffling[j]] = original[j];
		}
		original = num;
	}

	for (int i = 0; i<54; i++)
	{
		cout << original[i];
		if (i != 53) cout << " ";
	}
	return 0;
}

1041. Be Unique (20)

1.题目要求求一个数组中,第一个出现的仅出现一次(Unique)的数字。

2.统计各个数字出现的次数。

3.输出第一个出现次数为1的数字。

时间限制
100 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Being unique is so important to people on Mars that even their lottery is designed in a unique way. The rule of winning is simple: one bets on a number chosen from [1, 104]. The first one who bets on a unique number wins. For example, if there are 7 people betting on 5 31 5 88 67 88 17, then the second one who bets on 31 wins.

Input Specification:

Each input file contains one test case. Each case contains a line which begins with a positive integer N (<=105) and then followed by N bets. The numbers are separated by a space.

Output Specification:

For each test case, print the winning number in a line. If there is no winner, print “None” instead.

Sample Input 1:

7 5 31 5 88 67 88 17

Sample Output 1:

31

Sample Input 2:

5 888 666 666 888 888

Sample Output 2:

None

 
AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

int main(void)
{

	int *frequency = new int[100001];
	memset(frequency, 0, 100001 * sizeof(int));
	int sum;
	cin >> sum;
	int *num = new int[sum];
	for (int i = 0; i<sum; i++)
	{
		scanf("%d", &num[i]);
		frequency[num[i]]++;
	}
	for (int i = 0; i<sum; i++)
	{
		if (frequency[num[i]] == 1)
		{
			cout << num[i] << endl;
			return 0;
		}
	}
	cout << "None" << endl;
	return 0;
}

1040. Longest Symmetric String (25)

1.求最长回文子字符串。

2.getline输入数据。

3.最好使用manacher方法。

4.暴力方法解决不会超时。

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Given a string, you are supposed to output the length of the longest symmetric sub-string. For example, given “Is PAT&TAP symmetric?”, the longest symmetric sub-string is “s PAT&TAP s”, hence you must output 11.

Input Specification:

Each input file contains one test case which gives a non-empty string of length no more than 1000.

Output Specification:

For each test case, simply print the maximum length in a line.

Sample Input:

Is PAT&TAP symmetric?

Sample Output:

11

 
暴力AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;

int main(void)
{

	string  str;
	getline(cin,str);
	int maxLen = 0;
	for (int i = 0; i<str.size(); i++)
	{
		int oddLen = 1, evenLen = 0;
		for (int j = 1; i - j >= 0 && i + j<str.size(); j++)
		{
			if (str[i + j] == str[i - j])
				oddLen += 2;
			else break;
		}
		for (int j = 0; i - j >= 0 && i + j + 1<str.size(); j++)
		{
			if (str[i + j + 1] == str[i - j])
				evenLen += 2;
			else break;
		}
		maxLen = max(maxLen, max(oddLen, evenLen));
	}
	cout << maxLen << endl;
	return 0;
}

1039. Course List for Student (25)

1.题目给出一些课程和选修的学生名单,最后查询学生选修了什么课程。

2.存在超时的危险。

3.根据题意,名字由3个字母和1个数字组成,所以共26*26*26*10=175760种可能,直接开辟内存。

20151116133921234

时间限制
200 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Zhejiang University has 40000 students and provides 2500 courses. Now given the student name lists of all the courses, you are supposed to output the registered course list for each student who comes for a query.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers: N (<=40000), the number of students who look for their course lists, and K (<=2500), the total number of courses. Then the student name lists are given for the courses (numbered from 1 to K) in the following format: for each course i, first the course index i and the number of registered students Ni (<= 200) are given in a line. Then in the next line, Ni student names are given. A student name consists of 3 capital English letters plus a one-digit number. Finally the last line contains the N names of students who come for a query. All the names and numbers in a line are separated by a space.

Output Specification:

For each test case, print your results in N lines. Each line corresponds to one student, in the following format: first print the student’s name, then the total number of registered courses of that student, and finally the indices of the courses in increasing order. The query results must be printed in the same order as input. All the data in a line must be separated by a space, with no extra space at the end of the line.

Sample Input:

11 5
4 7
BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
1 4
ANN0 BOB5 JAY9 LOR6
2 7
ANN0 BOB5 FRA8 JAY9 JOE4 KAT3 LOR6
3 1
BOB5
5 9
AMY7 ANN0 BOB5 DON2 FRA8 JAY9 KAT3 LOR6 ZOE1
ZOE1 ANN0 BOB5 JOE4 JAY9 FRA8 DON2 AMY7 KAT3 LOR6 NON9

Sample Output:

ZOE1 2 4 5
ANN0 3 1 2 5
BOB5 5 1 2 3 4 5
JOE4 1 2
JAY9 4 1 2 4 5
FRA8 3 2 4 5
DON2 2 4 5
AMY7 1 5
KAT3 3 2 4 5
LOR6 4 1 2 4 5
NON9 0

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
/*
ZOE1 2 4 5
ANN0 3 1 2 5
BOB5 5 1 2 3 4 5
JOE4 1 2
JAY9 4 1 2 4 5
FRA8 3 2 4 5
DON2 2 4 5
AMY7 1 5
KAT3 3 2 4 5
LOR6 4 1 2 4 5
NON9 0
*/
int main(void)
{

	int querySum, courseSum;
	cin >> querySum >> courseSum;
	vector<set<int>>stu(175761);//3个字母+1个数字,共26*26*26*10=175760种可能,直接开辟内存
	for (int i = 0; i<courseSum; i++)
	{
		int courseIdx, studentSum;
		scanf("%d %d", &courseIdx, &studentSum);
		for (int j = 0; j<studentSum; j++)
		{
			char tmp[5];
			scanf("%s", tmp);
			int name = (tmp[0]-'A')*26*26*10;
			name += (tmp[1] - 'A') * 26*10 + (tmp[2] - 'A') * 10 + tmp[3]-'0';
			stu[name].insert(courseIdx);
		}
	}

	for (int i = 0; i<querySum; i++)
	{
		char tmp[5];
		scanf("%s", tmp);
		int name = (tmp[0] - 'A') * 26 * 26 * 10;
		name += (tmp[1] - 'A') * 26 * 10 + (tmp[2] - 'A') * 10 + tmp[3] - '0';
		printf("%s %d",tmp,stu[name].size());
		for (set<int>::iterator ite = stu[name].begin(); ite != stu[name].end(); ite++)
		{
			printf(" %d", *ite);
		}
		cout << endl;
	}

	return 0;
}

1038. Recover the Smallest Number (30)

1.题目是把一些数,通过组合,变成一个最小的数(在这些数的所有组合中最小)

2.使用贪心算法,贪心标准为:

1)如果两个数中,数a是数b的前缀,或者数b是数a的前缀,那么判断字符串相加后a+b与b+a的大小,进行确定前后顺序

2)如果不是上面1)中的两种情况,直接按照string进行大小比较

3.该题目可以通过微小的修改,改为求最大的数。

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Given a collection of number segments, you are supposed to recover the smallest number from them. For example, given {32, 321, 3214, 0229, 87}, we can recover many numbers such like 32-321-3214-0229-87 or 0229-32-87-321-3214 with respect to different orders of combinations of these segments, and the smallest number is 0229-321-3214-32-87.

Input Specification:

Each input file contains one test case. Each case gives a positive integer N (<=10000) followed by N number segments. Each segment contains a non-negative integer of no more than 8 digits. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the smallest number in one line. Do not output leading zeros.

Sample Input:

5 32 321 3214 0229 87

Sample Output:

22932132143287

 
AC代码:

#include <iostream>
#include <stdio.h>
#include <vector>
#include <stack>
#include <algorithm>
#include <memory.h>
#include "limits.h"
using namespace std;

bool cmp(const string&a,const string&b)
{
    //如果a和b,是前缀关系是,要比较a+b与b+a的大小
    if(a.size()<b.size()&&a==b.substr(0,a.size()))
        return a+b<b+a;
    else if(b.size()<a.size() && b==a.substr(0,b.size()))
        return a+b<b+a;
    else return a<b;
}
/*
 5 32 321 3214 0229 87
 4 11 122 12 10
 4  122 12 10 11
 */

int main(void)
{
    int n;
    cin>>n;
    vector<string> str(n);
    for(int i=0;i<n;i++)
    {
        cin>>str[i];
    }
    sort(str.begin(), str.end(),cmp);
    string ans="";
    for(int i=0;i<n;i++)
    {
        ans+=str[i];
    }
    int i=0;
    while(ans[i] == '0')
    {
        i++;
    }
    //注意全为0的状态
    if(ans.substr(i)=="") cout<<0<<endl;
    else cout<<ans.substr(i)<<endl;
    return 0;
}

1037. Magic Coupon (25)

1.题目给出一些coupon和product,求最大的value。

2.最大的正数coupon与最大的正数product相乘。

3.最小的负数coupon与最小的负数product相乘(最小的负数即绝对值最大)。

4.其他没有匹配的就不购买了。

时间限制
100 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

The magic shop in Mars is offering some magic coupons. Each coupon has an integer N printed on it, meaning that when you use this coupon with a product, you may get N times the value of that product back! What is more, the shop also offers some bonus product for free. However, if you apply a coupon with a positive N to this bonus product, you will have to pay the shop N times the value of the bonus product… but hey, magically, they have some coupons with negative N’s!

For example, given a set of coupons {1 2 4 -1}, and a set of product values {7 6 -2 -3} (in Mars dollars M$) where a negative value corresponds to a bonus product. You can apply coupon 3 (with N being 4) to product 1 (with value M$7) to get M$28 back; coupon 2 to product 2 to get M$12 back; and coupon 4 to product 4 to get M$3 back. On the other hand, if you apply coupon 3 to product 4, you will have to pay M$12 to the shop.

Each coupon and each product may be selected at most once. Your task is to get as much money back as possible.

Input Specification:

Each input file contains one test case. For each case, the first line contains the number of coupons NC, followed by a line with NC coupon integers. Then the next line contains the number of products NP, followed by a line with NP product values. Here 1<= NC, NP <= 105, and it is guaranteed that all the numbers will not exceed 230.

Output Specification:

For each test case, simply print in a line the maximum amount of money you can get back.

Sample Input:

4
1 2 4 -1
4
7 6 -2 -3

Sample Output:

43

AC代码:

//#include<string>
//#include <iomanip>
#include<vector>
#include <algorithm>
//#include<stack>
#include<set>
#include<queue>
#include<map>
//#include<unordered_set>
#include<unordered_map>
//#include <sstream>
//#include "func.h"
//#include <list>
#include<stdio.h>
#include<iostream>
#include<string>
#include<memory.h>
#include<limits.h>
using namespace std;
bool cmp(const int&a, const int&b)
{
	return a > b;
}
int main(void)
{
	int n;
	
	vector<int> couponP(0);
	vector<int> couponN(0);
	vector<int> productP(0);
	vector<int> productN(0);
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int a;
		scanf("%d", &a);
		if (a < 0) couponN.push_back(a);
		else couponP.push_back(a);
	}

	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int a;
		scanf("%d", &a);
		if (a < 0) productN.push_back(a);
		else productP.push_back(a);
	}
	sort(couponP.begin(), couponP.end(), cmp);
	sort(couponN.begin(), couponN.end());
	sort(productP.begin(), productP.end(), cmp);
	sort(productN.begin(), productN.end());
	int sum = 0;
	for (int i = 0; i < couponP.size() && i < productP.size(); i++)
		sum += couponP[i] * productP[i];
	for (int i = 0; i < couponN.size() && i < productN.size(); i++)
		sum += couponN[i] * productN[i];
	cout << sum << endl;
	return 0;
}

1121 二分图一•二分图判定

1.使用顶点的数据结构存储图

//使用顶点的结构来存储图
vector<vector<int>> graph(n, vector<int>(0));

2.使用BFS遍历每个顶点,对每个顶点的邻居进行判断,未染色则进行染色,如果染色了则判断是否合理。

3.图有可能不连通,因此使用sum来记录已经遍历过的顶点数,如果发现没有完全遍历,则再次寻找没有染色的节点,染色后重复步骤2

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

描述

大家好,我是小Hi和小Ho的小伙伴Nettle,从这个星期开始由我来完成我们的Weekly。

新年回家,又到了一年一度大龄剩男剩女的相亲时间。Nettle去姑姑家玩的时候看到了一张姑姑写的相亲情况表,上面都是姑姑介绍相亲的剩男剩女们。每行有2个名字,表示这两个人有一场相亲。由于姑姑年龄比较大了记性不是太好,加上相亲的人很多,所以姑姑一时也想不起来其中有些人的性别。因此她拜托我检查一下相亲表里面有没有错误的记录,即是否把两个同性安排了相亲。

OK,让我们愉快的暴力搜索吧!

才怪咧。

对于拿到的相亲情况表,我们不妨将其转化成一个图。将每一个人作为一个点(编号1..N),若两个人之间有一场相亲,则在对应的点之间连接一条无向边。(如下图)

因为相亲总是在男女之间进行的,所以每一条边的两边对应的人总是不同性别。假设表示男性的节点染成白色,女性的节点染色黑色。对于得到的无向图来说,即每一条边的两端一定是一白一黑。如果存在一条边两端同为白色或者黑色,则表示这一条边所表示的记录有误。

由于我们并不知道每个人的性别,我们的问题就转化为判定是否存在一个合理的染色方案,使得我们所建立的无向图满足每一条边两端的顶点颜色都不相同

那么,我们不妨将所有的点初始为未染色的状态。随机选择一个点,将其染成白色。再以它为起点,将所有相邻的点染成黑色。再以这些黑色的点为起点,将所有与其相邻未染色的点染成白色。不断重复直到整个图都染色完成。(如下图)

在染色的过程中,我们应该怎样发现错误的记录呢?相信你一定发现了吧。对于一个已经染色的点,如果存在一个与它相邻的已染色点和它的颜色相同,那么就一定存在一条错误的记录。(如上图的4,5节点)

到此我们就得到了整个图的算法:

  1. 选取一个未染色的点u进行染色
  2. 遍历u的相邻节点v:若v未染色,则染色成与u不同的颜色,并对v重复第2步;若v已经染色,如果 u和v颜色相同,判定不可行退出遍历。
  3. 若所有节点均已染色,则判定可行。

接下来就动手写写吧!

输入

第1行:1个正整数T(1≤T≤10)

接下来T组数据,每组数据按照以下格式给出:

第1行:2个正整数N,M(1≤N≤10,000,1≤M≤40,000)

第2..M+1行:每行两个整数u,v表示u和v之间有一条边

输出

第1..T行:第i行表示第i组数据是否有误。如果是正确的数据输出”Correct”,否则输出”Wrong”

样例输入
2
5 5
1 2
1 3
3 4
5 2
1 5
5 5
1 2
1 3
3 4
5 2
3 5
样例输出
Wrong
Correct

 
AC代码:

//#include<string>  
//#include<stack>  
//#include<unordered_set>  
//#include <sstream>  
//#include "func.h"  
//#include <list>  
#include <iomanip>  
#include<unordered_map>  
#include<set>  
#include<queue>  
#include<map>  
#include<vector>  
#include <algorithm>  
#include<stdio.h>  
#include<iostream>  
#include<string>  
#include<memory.h>  
#include<limits.h>  
#include<stack>
using namespace std;

int main(void) {

	int t;
	cin >> t;
	while (t--)
	{
		int n, m;
		scanf("%d %d", &n, &m);
		n++;

		//使用顶点的结构来存储图
		vector<vector<int>> graph(n, vector<int>(0));
		for (int i = 0; i < m; i++)
		{//读取顶点关系
			int a, b;
			scanf("%d %d", &a, &b);
			graph[a].push_back(b);
			graph[b].push_back(a);
		}
		vector<int> sex(n, -1);//定义大小为n的sex数组,用来标记用户的性别,0为男,1为女
		sex[1] = 0;
		queue<int> q;
		q.push(1);
		bool flag = true;
		int sum = 1;//染色的总个数
		//使用BFS进行搜索
		while (1)
		{
			int p = q.front();
			for (int i = 0; i < graph[p].size(); i++)
			{
				if (sex[graph[p][i]] == -1)
				{//如果还没染色,就进行染色
					sex[graph[p][i]] = 1 - sex[p];//相邻顶点性别不同
					q.push(graph[p][i]);
					sum++;
				}
				else if (sex[graph[p][i]] != -1 && sex[graph[p][i]] == sex[p])
				{//如果已经染色,并且性别相同,则Wrong,直接跳出循环
					flag = false;
					break;
				}
			}
			q.pop();
			if (q.empty() && sum == n - 1) break;//已经全部遍历完毕
			else if (q.empty() && sum < n - 1)
			{//队列为空,但是还有没有遍历的顶点,证明不是连通图
				for (int i = 1; i < n; i++)
				{
					if (sex[i] == -1)
					{//图可能不连通,找出其他分支的一个点进行染色,并马上break
						sex[i] = 1;
						q.push(i);
						sum++;
						break;//break
					}
				}
			}
		}
		if (flag) cout << "Correct" << endl;
		else cout << "Wrong" << endl;
	}
	return 0;
}


new和malloc的区别

转自:http://www.cnblogs.com/fly1988happy/archive/2012/04/26/2470542.html

1. malloc()函数

1.1 malloc的全称是memory allocation,中文叫动态内存分配。

原型:extern void *malloc(unsigned int num_bytes); 

说明:分配长度为num_bytes字节的内存块。如果分配成功则返回指向被分配内存的指针,分配失败返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。

1.2 void *malloc(int size); 

说明:malloc 向系统申请分配指定size个字节的内存空间,返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。   

备注:void* 表示未确定类型的指针,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者…)

1.3 free

void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

1.4注意事项

1)申请了内存空间后,必须检查是否分配成功

2)当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。 

3)这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

4)虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。

1.5  malloc()到底从哪里得到了内存空间?

答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

2. new运算符

2.1 C++中,用new和delete动态创建和释放数组或单个对象

动态创建对象时,只需指定其数据类型,而不必为该对象命名,new表达式返回指向该新创建对象的指针,我们可以通过指针来访问此对象

int *pi=new int;

这个new表达式在堆区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi 。

2.2 动态创建对象的初始化

动态创建的对象可以用初始化变量的方式初始化。

int *pi=new int(100); //指针pi所指向的对象初始化为100

string *ps=new string(10,’9’);//*ps 为“9999999999”

如果不提供显示初始化,对于类类型,用该类的默认构造函数初始化;而内置类型的对象则无初始化

也可以对动态创建的对象做值初始化:

int *pi=new int( );//初始化为0

int *pi=new int;//pi 指向一个没有初始化的int

string *ps=new string( );//初始化为空字符串 (对于提供了默认构造函数的类类型,没有必要对其对象进行值初始化)

2.3 撤销动态创建的对象

delete表达式释放指针指向的地址空间。

delete pi ;// 释放单个对象

delete [ ]pi;//释放数组

如果指针指向的不是new分配的内存地址,则使用delete是不合法的。

2.4 在delete之后,重设指针的值

delete p; //执行完该语句后,p变成了不确定的指针,在很多机器上,尽管p值没有明确定义,但仍然存放了它之前所指对象的地址,然后p所指向的内存已经被释放了,所以p不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。

一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;)

2.5 区分零值指针和NULL指针

零值指针,是值是0的指针,可以是任何一种指针类型,可以是通用变体类型void*也可以是char*,int*等等。

空指针,其实空指针只是一种编程概念,就如一个容器可能有空和非空两种基本状态,而在非空时可能里面存储了一个数值是0,因此空指针是人为认为的指针不提供任何地址讯息。参考:http://www.cnblogs.com/fly1988happy/archive/2012/04/16/2452021.html

2.6 new分配失败时,返回什么?

1993年前,c++一直要求在内存分配失败时operator   new要返回0,现在则是要求operator   new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator   new(以及operator   new[])以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象

class   widget   {   …   };

widget   *pw1   =   new   widget;//   分配失败抛出std::bad_alloc  

if   (pw1   ==   0)   … //   这个检查一定失败

widget   *pw2   =   new   (nothrow)   widget;   //   若分配失败返回0

if   (pw2   ==   0)   … //   这个检查可能会成功

3. malloc和new的区别

3.1 new 返回指定类型的指针,并且可以自动计算所需要大小。

比如:   

1) int *p;   

p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int);   

或:   

int* parr;   

parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为 sizeof(int) * 100;   

2) 而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。   

int* p;   

p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中  

double *pd=(double *) malloc (sizeof(double)*12);//分配12个double型存储单元,并将首地址存储到指针变量pd中

3.2 malloc 只管分配内存,并不能对所得的内存进行初始化所以得到的一片新内存中,其值将是随机的

除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。

4.有了malloc/free为什么还要new/delete?

1) malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。

2) 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。

因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。

3) 既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。

如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,结果也会导致程序出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。

算法设计:统计页码数字问题

问题描述:

一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6 页用数字6 表示,而不是06 或006 等。数

字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。

 

一、思路:

  • 以数字1为例子,我们把求1出现的次数,转化为求1~n中,各个位出现1的次数的总和。即个位上出现1的次数,十位上出现1的次数,百位上出现1的次数……的总和。

取变量m,当m=1时,即求个位上出现1的总次数,m=100时,即求百位上出现1的总次数。假设n=3141592,求百位上1出现的总次数,我们把n分为两部分,分别是整除m后得到部分a=n/100=31415,和整除m后的余数部分b=n%100=92。

  • 对于31415,我们求0~31415中,个位1出现的次数,即31415/10=3141,又因为31415%10=5大于1,所以0~31415中,各位出现1的总次数为3141+1=3142.实际上,31415是除以100后得到的数,所以每个1,出现了100次。如3141100~3141199,百位上的1出现了100次,所以这时候百位上的1出现次数为(31415/10+1)*100=314200次。
  • 再考察第二部分b=92.因为a%10=5,而不是1。所以第二部分没有贡献1。假设n=9999150,那么a=n/100=99991,由a部分计算得百位上出现1的次数为a/10*100=9999000次。而a%10=1,那么第二部分b=50将会有作用,贡献的1的次数为b+1,即9999100~9999150百位上供50+1,即51次1.所以当n=9999150时,百位上出现1的次数为9999050次。
  • 通过上述思路,我们可以分别计算个位出现1的次数,十位出现1的次数……,通过相加,我们可以得到1~n中,1出现的总次数。
  • 通过上述思路,我们可以分别计算0~9出现的总次数。
  • 数字0的情况有点特殊,进行特殊处理。因为不会出现01,02,03等等0开头的数字,所以在统计数字零时,每个位计算出来的count,如果count>=1,则需要先count–,再进行计算。

 

二、复杂度分析

根据上述算法,我们通过逐渐计算n的个位,十位,百位……即每次m*=10,所以时间复杂度是O(lg n),在空间方面,每次固定使用常量a和b,估空间负责度不依赖于n,所以空间复杂度啊为O(1)。

 

数据测试结果如下:采取了临界值1和1000000000(10^9)

n=1 n=10^9 n=100 n=555555 n=99 n=200 201
0的个数 0 788888898 11 271605 9 31 21
1的个数 1 900000001 21 382716 20 140 141
2的个数 0 900000000 20 382716 20 41 42
3的个数 0 900000000 20 382716 20 40 40
4的个数 0 900000000 20 382716 20 40 40
5的个数 0 900000000 20 333336 20 40 40
6的个数 0 900000000 20 271605 20 40 40
7的个数 0 900000000 20 271605 20 40 40
8的个数 0 900000000 20 271605 20 40 40
9的个数 0 900000000 20 271605 20 40 40

 

三、程序运行截图如下:

tongji

 

四、源代码

代码中,通过类Solution封装了void calEveryDigitNumberint n)函数:


class Solution
{
private:
	/**************************************
	Author:siukwan
	Date:2015-09-25
	Description:计算digit出现的次数
	***************************************/
	static int calOneDigit(int n, int digit)
	{
		int ans = 0;//返回的结果
		for (long long m = 1; m <= n; m *= 10)
		{//m采用long long类型,避免溢出,从计算个位出现digit的次数开始
			int a = n / m;
			int b = n % m;
			int count = a / 10;
			if (a % 10 > digit) count++;//如果a的余数部分大于digit,则会多出现m个digit
			if (digit == 0 && count >=1 ) count--;//0需要特殊处理,因为没有01,02,03……
			ans += count * m;//计算a部分出现digit的次数
			if (a % 10 == digit )
					ans += (b + 1);//如果余数恰好等于digit,结合b部分统计额外出现digit的次数
		}
		return ans;
	}
public:
	/**************************************
	Author:siukwan
	Date:2015-09-25
	Description:计算0~9出现的次数,并输出结果
	***************************************/
	static void calEveryDigitNumber(int n)
	{
		for (int i = 0; i < 9; i++)
		{
			int count = calOneDigit(n, i);
			printf("%d出现的次数:%d\n", i, count);
		}
	}
};

 

整个程序的代码如下:

#include<stdio.h>
#include<iostream>
using namespace std;
class Solution
{
private:
	/**************************************
	Author:siukwan
	Date:2015-09-25
	Description:计算digit出现的次数
	***************************************/
	static int calOneDigit(int n, int digit)
	{
		int ans = 0;//返回的结果
		for (long long m = 1; m <= n; m *= 10)
		{//m采用long long类型,避免溢出,从计算个位出现digit的次数开始
			int a = n / m;
			int b = n % m;
			int count = a / 10;
			if (a % 10 > digit) count++;//如果a的余数部分大于digit,则会多出现m个digit
			if (digit == 0 && count >=1 ) count--;//0需要特殊处理,因为没有01,02,03……
			ans += count * m;//计算a部分出现digit的次数
			if (a % 10 == digit )
					ans += (b + 1);//如果余数恰好等于digit,结合b部分统计额外出现digit的次数
		}
		return ans;
	}
public:
	/**************************************
	Author:siukwan
	Date:2015-09-25
	Description:计算0~9出现的次数,并输出结果
	***************************************/
	static void calEveryDigitNumber(int n)
	{
		for (int i = 0; i < 9; i++)
		{
			int count = calOneDigit(n, i);
			printf("%d出现的次数:%d\n", i, count);
		}
	}
};
int main(void)
{
	int n = 0;
	while (1)
	{
		printf("算法实现题1-1:统计数字问题\n1)本程序会统计1~n的n个数字中,0~9分别出现的次数;\n2)n的取值范围为0<=n<=10^9;\n请输入页码n:");

		cin >> n;
		if (n <= 0 || n>1000000000)
		{
			printf("n的取值范围为0<=n<=10^9,请重新输入!\n");
			continue;
		}
		Solution::calEveryDigitNumber(n);
	}
	return 0;
}