1069. The Black Hole of Numbers (20)

1. 6174猜想 ,1955年,卡普耶卡(D.R.Kaprekar)研究了对四位数的一种变换:任给出四位数k0,用它的四个数字由大到小重新排列成一个四位数m,再减去它的反序数rev(m),得出数k1=m-rev(m),然后,继续对k1重复上述变换,得数k2.如此进行下去,卡普耶卡发现,无论k0是多大的四位数, 只要四个数字不全相同,最多进行7次上述变换,就会出现四位数6174.

2.需要注意输入的数字不一定是4位的,需要转化为4位的string进行处理,如输入1,2,3,4。

3.输入为6174时,应该输出7641 – 1467  = 6174。一开始卡在这个测试点了。

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

For any 4-digit integer except the ones with all the digits being the same, if we sort the digits in non-increasing order first, and then in non-decreasing order, a new number can be obtained by taking the second number from the first one. Repeat in this manner we will soon end up at the number 6174 — the “black hole” of 4-digit numbers. This number is named Kaprekar Constant.

For example, start from 6767, we’ll get:

7766 – 6677 = 1089
9810 – 0189 = 9621
9621 – 1269 = 8352
8532 – 2358 = 6174
7641 – 1467 = 6174
… …

Given any 4-digit number, you are supposed to illustrate the way it gets into the black hole.

Input Specification:

Each input file contains one test case which gives a positive integer N in the range (0, 10000).

Output Specification:

If all the 4 digits of N are the same, print in one line the equation “N – N = 0000”. Else print each step of calculation in a line until 6174 comes out as the difference. All the numbers must be printed as 4-digit numbers.

Sample Input 1:

6767

Sample Output 1:

7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174

Sample Input 2:

2222

Sample Output 2:

2222 - 2222 = 0000

AC代码:

//#include<string>
//#include <iomanip>
//#include<stack>
//#include<unordered_set>
//#include <sstream>
//#include "func.h"
//#include <list>
#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;
/*
测试案例(不一定是4位数):
6174
需要输出7641 - 1467 = 6174

1

2

3

4

5

6
*/
bool cmp(const char&a, const char&b)
{
	return a > b;
}
string num2str(int a)
{
	a += 10000;//如果有0,则相当于补充千位,百位的0
	string ans = "";
	for (int i = 1; i < 5; i++)
	{
		char c = a % 10 + '0';
		ans = c + ans;
		a /= 10;
	}
	return ans;
}
int str2num(string s)
{
	return (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
}
int main(void)
{
	int num;
	cin >> num;
	string s = num2str(num);
	char c = s[0];
	bool isSame = true;
	for (int i = 0; i < 4; i++)
	{
		if(s[i] != c)
		{
			isSame = false;
			break;
		}
	}
	if (isSame)
	{//如果所有位相同,直接输出0000
		cout << s << " - " << s << " = 0000" << endl;
	}
	else
	{
		string ans = "";//这样处理使得输入为6174时,也能输出7641 - 1467 = 6174
		while (ans != "6174")
		{
			sort(s.begin(), s.end(), cmp);
			string a = s;//大到小排列
			sort(s.begin(), s.end());
			string b = s;//小到大排列
			int tmp = str2num(a) - str2num(b);
			ans = num2str(tmp);
			cout << a << " - " << b << " = " << ans << endl;
			s = ans;

		}
	}
	return 0;
}

1068. Find More Coins (30)

1.题目要求在一个数组中,找出和为M的元素。

2.这道题目采用深度遍历,因为M的值<=100,即需求最大是100,因为硬币价值是正数,那么最多需要100个硬币,即进行DFS的深度为100,可以接受

3.需要进行剪枝:

1)把coin价值从小到大排列;

2)从第一个开始遍历,如果价格减去这个硬币的价值后,剩下的价格小于这个硬币的价值,那么可以continue。因为后面的硬币价值都大于等于现在硬币的价值,有一种情况例如,就是价格减去这个硬币的价值后,刚好等于0,那么就可以输出答案;

3)按照上述从小到大排列,第一次获得的答案,肯定为最小的,此时可以直接跳出DFS,输出答案即可。

1068

 

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

Eva loves to collect coins from all over the universe, including some other planets like Mars. One day she visited a universal shopping mall which could accept all kinds of coins as payments. However, there was a special requirement of the payment: for each bill, she must pay the exact amount. Since she has as many as 104 coins with her, she definitely needs your help. You are supposed to tell her, for any given amount of money, whether or not she can find some coins to pay for it.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive numbers: N (<=104, the total number of coins) and M(<=102, the amount of money Eva has to pay). The second line contains N face values of the coins, which are all positive numbers. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print in one line the face values V1 <= V2 <= … <= Vk such that V1 + V2 + … + Vk = M. All the numbers must be separated by a space, and there must be no extra space at the end of the line. If such a solution is not unique, output the smallest sequence. If there is no solution, output “No Solution” instead.

Note: sequence {A[1], A[2], …} is said to be “smaller” than sequence {B[1], B[2], …} if there exists k >= 1 such that A[i]=B[i] for all i < k, and A[k] < B[k].

Sample Input 1:

8 9
5 9 8 7 2 3 4 1

Sample Output 1:

1 3 5

Sample Input 2:

4 8
7 2 4 3

Sample Output 2:

No Solution

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;

void dfs(int nowIdx, int need, vector<int>&coin, vector<int>&solution, vector<vector<int>>&ans)
{
	if (need == 0)
	{
		ans.push_back(solution);
	}
	else
	{
		bool hasSolution = false;
		if (coin[nowIdx] > need) return;//不用进行下面的遍历,因为nowIdx后面的coin大于或等于现在的coin
		for (int i = nowIdx; i < coin.size(); i++)
		{
			if (hasSolution && coin[i] == coin[i - 1])
				continue;//这个硬币方案和上一个方案一样
			else
			{
				if (need - coin[i] < coin[i] && need!=coin[i]) continue;//如果这个硬币选了之后,剩下的价值比这个硬币小,则不可能,因为后面的硬币价值比现在这个大,除非这个硬币刚好等于need
				hasSolution = true;
				solution.push_back(coin[i]);
				dfs(i + 1, need - coin[i], coin, solution, ans);
				if (ans.size()) return;//有答案,则这个答案必然是最小的,进行剪枝
				solution.pop_back();

			}
			if (coin[i] == need) break;//这个已经是答案了,后面不可能存在不一样的答案,不用遍历
		}
	}
}

bool cmp(const vector<int>&a, const vector<int>&b)
{
	for (int i = 0; i < min(a.size(), b.size()); i++)
	{
		if (a[i] < b[i]) return true;
		else if (a[i] > b[i]) return false;
	}
	if (a.size() < b.size()) return true;
	else return false;
}

int main(void)
{
	int n, need;
	cin >> n >> need;
	vector<int> coin(n);
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &coin[i]);
	}
	vector<int> solution(0);
	vector<vector<int>> ans(0);
	sort(coin.begin(), coin.end());
	dfs(0, need, coin, solution, ans);
	sort(ans.begin(), ans.end(),cmp);
	if (ans.size() == 0)
		cout << "No Solution" << endl;
	else
	{
		for (int i = 0; i < ans[0].size(); i++)
		{
			printf("%d", ans[0][i]);
			if (i != ans[0].size() - 1)
				printf(" ");
		}
		cout << endl;
	}
	return 0;
}

1067. Sort with Swap(0,*) (25)

1.题目要求只允许交换0和其他数值,最后得到一个排序的数组,求最小的交换次数。注意是交换0,而不是交换0这个位置上的值。譬如10567,swap(0,6)后得到16507.

2.用一个数组pos记录各个元素所在的位置

3.假设0所在的位置为i,那么正确的排序应该是i在位置i上,所以0应该和i交换,即0的位置和i的位置交换,swap(pos[0],pos[i]),又pos[0]=i,即0的位置在i上,所以swap(pos[0],pos[pos[0]])。

4.通过3中提到的,每次都把一个数换到正确的位置,步数最小。

5.可能还存在尚未结束,但是0已经在位置0上,此时进行交换,对排序没有帮助,于是我们需要把0和任意一个不符合pos[i]=i要求的数进行交换,然后再进行上述的步骤。

6.需要记录上次是哪个i不满足pos[i]=i的要求,这样才能AC,不然会超时(即每次都得从0搜索到n-1,会超时)

1067

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

Given any permutation of the numbers {0, 1, 2,…, N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, …, N-1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:

10 3 5 7 2 6 4 9 0 8 1

Sample Output:

9

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 n;
	cin >> n;
	vector<int> num(n);
	vector<int> pos(n);
	int disorderPos = -1;//记录不合要求的第一个位置
	for (int i = 0; i < n; i++)
	{
		int tmp;
		scanf("%d", &tmp);
		pos[tmp] = i;//记录tmp所在位置i
		if (tmp != i&&disorderPos == -1) disorderPos = i;
	}
	int step = 0;
	while (1)
	{
		if (pos[0] != 0)
		{//把0所在的位置pos[0]=i换成数字i,此时数字i在位置pos[i]上,所以需要swap(pos[0], pos[pos[0]]);
			swap(pos[0], pos[pos[0]]);
			step++;
		}
		else
		{
			for (; disorderPos < pos.size(); disorderPos++)
				if (pos[disorderPos] != disorderPos)//找出不合要求的数
					break;
			if (disorderPos == pos.size()) break;
			swap(pos[0], pos[disorderPos]);
			step++;
		}
	}
	cout << step << endl;
	return 0;
}

303 Range Sum Query – Immutable(easy)

1.这道题目与pat中的1046. Shortest Distance (20)相类似;
2.使用一个数组dp[i],记录0到第i个数的和
3.求i到j之间的和时,输出dp[j]-dp[i]+num[i]即可。

Given an integer array nums, find the sum of the elements between indices i and j (ij), inclusive.

Example:

Given nums = [-2, 0, 3, -5, 2, -1]

sumRange(0, 2) -> 1
sumRange(2, 5) -> -1
sumRange(0, 5) -> -3

Note:

  1. You may assume that the array does not change.
  2. There are many calls to sumRange function.

Subscribe to see which companies asked this question

AC代码如下:

class NumArray {
public:

    vector<int> dp;
    vector<int> num;
    NumArray(vector<int> &nums) {
        int n=nums.size();
        dp=vector<int>(n,0);
        num=nums;
        for(int i=0;i<n;i++)         {             if(i>0)
                dp[i]=dp[i-1]+nums[i];
            else
                dp[0]=nums[0];
        }
    }

    int sumRange(int i, int j) {
        return dp[j]-dp[i]+num[i];
    }
};

// Your NumArray object will be instantiated and called as such:
// NumArray numArray(nums);
// numArray.sumRange(0, 1);
// numArray.sumRange(1, 2);

233 Number of Digit One(Medium)

1.算法说明:
如3141592,在m(digitDivide)=100时,即要求计算百位上“1”的个数
其中a为31415,b为92,31415中出现了3142次“1”,因为每10个数里面出现1次“1”。而实际上,31415是3141500,所以把31415中1的个数再乘以m。如3141400~3141499中,前缀为31414的数出现了100次,所以需要乘以m(此时是100)。

2.注意溢出的问题,所以在for循环里面,使用了long long类型。

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

Hint:

  1. Beware of overflow.

Subscribe to see which companies asked this question

class Solution {
    public:
    int countDigitOne(int n) {        

        int ans=0;
        for(long long digitDivide=1;digitDivide<=n;digitDivide*=10)
        {
            int a=n/digitDivide;
            int b=n%digitDivide;
            ans+=(a+8)/10*digitDivide+(a%10==1)*(b+1);
        }
        return ans;

    }};

226 Invert Binary Tree(easy)

1.直接用递归把左右子树翻转即可(仅针对二叉树的情况)。

2.时间复杂度为O(n),即遍历所有节点一次

Invert a binary tree.

     4
   /   \
  2     7
 / \   / \
1   3 6   9

to

     4
   /   \
  7     2
 / \   / \
9   6 3   1

Trivia:
This problem was inspired by this original tweet by Max Howell:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.

Subscribe to see which companies asked this question

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void invert(TreeNode* root)
    {
    	if (root != NULL)
    	{
    		swap(root->left, root->right);
    		invert(root->left);
    		invert(root->right);
    	}

    }
    TreeNode* invertTree(TreeNode* root) {
            invert(root);
            return root;
    }

};

1122 二分图二•二分图最大匹配之匈牙利算法

1.为了求最大匹配,我们可以把顶点集分为左边集合和右边集合,那么我们希望每一个在左边的点都尽量找到右边的一个点和它匹配。

2.依次遍历左边集合中点x的邻居y(y在右边集合中),如果y之前没有被匹配,那么(x,y)形成一个匹配,匹配数+1;如果y已经被匹配,假设x’与y匹配,那么尝试给x’找一个新的匹配,如果x’能够有一个新的匹配y’,那么匹配从原来的(x’,y)变为(x’y’)和(x,y),匹配数+1。

3.给x’找匹配的过程可以利用递归解决。

4.最后题目中提到两个优化:

(1)把顶点分为两个集合,只遍历其中一个集合即可,因为最大匹配数不超过任意一个集合的大小。另外,假设不分为两个集合,我们依次遍历所有顶点,那么我们得到的匹配数maxMatch会是所求答案的两倍,所以不分集合时,输出maxMatch/2。

(2)在遍历点x时,增加一个访问数组,标记点i是否被访问过,如果被访问过,那么在递归的时候就没必要再次访问判断了。每次遍历新的点时,这个访问数组需要清零。

5.采用如下数据结构:

struct UserNode{
	vector<int> list;//user的邻居
	int type;//user类型
	int from;//与user匹配的点 from--->user
	UserNode() :list(0), type(-1),from(-1){};
};

题目如下:

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

描述

上一回我们已经将所有有问题的相亲情况表剔除了,那么接下来要做的就是安排相亲了。因为过年时间并不是很长,所以姑姑希望能够尽可能在一天安排比较多的相亲。由于一个人同一天只能和一个人相亲,所以要从当前的相亲情况表里选择尽可能多的组合,且每个人不会出现两次。不知道有没有什么好办法,对于当前给定的相亲情况表,能够算出最多能同时安排多少组相亲呢?

同样的,我们先将给定的情况表转换成图G=(V,E)。在上一回中我们已经知道这个图可以被染成黑白两色。不妨将所有表示女性的节点记为点集A,表示男性的节点记为点集B。则有A∪B=V。由问题可知所有边e的两个端点分别属于AB两个集合。则可以表示成如下的图:

同样的,我们将所有的边分为两个集合。集合S和集合M,同样有S∪M=E。边集S表示在这一轮相亲会中将要进行的相亲,边集M表示在不在这一次进行。对于任意边(u,v) ∈ S,我们称u和v为一组匹配,它们之间相互匹配。在图G,我们将边集S用实线表示,边集M用虚线表示。得到下图:

则原问题转化为,最多能选择多少条边到集合S,使得S集合中任何两条边不相邻(即有共同的顶点)。显然的,|S|<=Min{|A|, |B|}。

那么能不能找到一个算法,使得能够很容易计算出尽可能多的边能够放入集合S?我们不妨来看一个例子:

对于已经匹配的点我们先不考虑,我们从未匹配的点来做。这里我们选择A集合中尚未匹配的点(A3和A4)考虑:

对于A3点,我们可以发现A3与B4右边相连,且都未匹配。则直接将(A3,B4)边加入集合S即可。

对于A4点,我们发现和A4相连的B3,B4点都已经匹配了。但是再观察可以发现,如果我们将A2和B2相连,则可以将B3点空出来。那么就可以同时将(A2,B2),(A4,B3)相连。将原来的一个匹配变成了两个匹配。

让我们来仔细看看这一步:我们将这次变换中相关联的边标记出来,如下图所示紫色的3条边(A2,B2),(A2,B3),(A4,B3)。

这三条边构成了一条路径,可以发现这条路径有个非常特殊的性质。虚线和实线相互交错,并且起点和终点都是尚未匹配的点,且属于两个不同的集合。我们称这样的路径为交错路径。

再进一步分析,对于任意一条交错路径,虚线的数量一定比实线的数量多1。我们将虚线和实线交换一下,就变成了下面的图:

在原来1个匹配的基础上,我们得到了2个新的匹配,S集合边的数量也增加了1。并且原来在已经匹配的点仍然是已经匹配的状态。

再回头看看A3点匹配时的情况:对于(A3,B4)这一条路径,同样满足了交错路径的性质。

至此我们得到了一个找新匹配的有效算法:

选取一个未匹配的点,查找是否存在一条以它为起点的交错路径。若存在,将该交错路径的边虚实交换。否则在当前的情况下,该点找不到可以匹配的点。

又有对于已经匹配的点,该算法并不会改变一个点的匹配状态。所以当我们对所有未匹配的点都计算过后,仍然没有交错路径,则不可能找到更多的匹配。此时S集合中的边数即为最大边数,我们称为最大匹配数。

那么我们再一次梳理整个算法:

1. 依次枚举每一个点i;
2. 若点i尚未匹配,则以此点为起点查询一次交错路径。

最后即可得到最大匹配数。

在这个基础上仍然有两个可以优化的地方:

1.对于点的枚举:当我们枚举了所有A中的点后,无需再枚举B中的点,就已经得到了最大匹配。
2.在查询交错路径的过程中,有可能出现Ai与Bj直接相连,其中Bj为已经匹配的点,且Bj之后找不到交错路径。之后又通过Ai查找到了一条交错路径{Ai,Bx,Ay,…,Az,Bj}延伸到Bj。由于之前已经计算过Bj没有交错路径,若此时再计算一次就有了额外的冗余。所以我们需要枚举每个Ai时记录B集合中的点是否已经查询过,起点不同时需要清空记录。

Function FindPath(u)
    For v∈u的相邻节点
       标记v已经查询过
       If v未匹配 or FindPath(v的匹配的点) Then
            更改u的匹配为v
            Return Ture
        End If
    End For
Return False

For i ∈ V
    清空标记
   FindPath(i)
End If

输入

第1行:2个正整数,N,M(N表示点数 2≤N≤1,000,M表示边数1≤M≤5,000)
第2..M+1行:每行两个整数u,v,表示一条无向边(u,v)

输出

第1行:1个整数,表示最大匹配数

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

AC代码分为两个版本,一个是两种优化都有的,一种是只进行第二种优化的(简洁很多,并且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;

/*
5 4
3 2
1 3
5 4
1 5

6 5
3 2
1 3
5 4
1 5
4 6
*/
struct UserNode{
	vector<int> list;//user的邻居
	int type;//user类型
	int from;//与user匹配的点 from--->user
	UserNode() :list(0), type(-1),from(-1){};
};
bool isMatch(int x, vector<bool>& visited, vector<UserNode>& user)
{
	for (auto neighbor:user[x].list)
	{//访问x的邻居
		if (!visited[neighbor])
		{//该邻居之前没有被访问,已被访问的证明已经进行了调整,不再访问遍历
			visited[neighbor] = true;
			if (user[neighbor].from == -1 || isMatch(user[neighbor].from,visited,user))
			{//如果邻居还没有被匹配,或者邻居原来的匹配点from可以有新的匹配
				user[neighbor].from = x;//把x与该邻居匹配
				return true;
			}
		}
	}
	//遍历了x的所有邻居后,发现不能匹配,则false
	return false;
}
int main(void) {

	int n, m;
	cin >> n >> m;
	if (n == 0)
	{
		cout << 0 << endl;
		return 0;
	}
	vector<UserNode> user(n);
	for (int i = 0; i < m; i++)
	{//输入边
		int a, b;
		scanf("%d %d", &a, &b);
		a--; b--;
		//构建图
		user[a].list.push_back(b);
		user[b].list.push_back(a);
	}
	queue<int> q;
	q.push(0);
	user[0].type = 1;
	int sum = 1;//相当于已经遍历0号顶点
	while (sum != user.size())//需要每个点都确定type
	{
		while (!q.empty())//BFS遍历确定每个顶点的type
		{
			int head = q.front();
			q.pop();
			for (auto neighbor : user[head].list)
			{//遍历head的邻居
				if (user[neighbor].type == -1)//尚未确定type
				{
					user[neighbor].type = 1 - user[head].type;
					q.push(neighbor);
					sum++;
				}
			}
		}
		if (sum != user.size())
		{//图不连通
			for (int i = 0; i < user.size();i++)
			{
				if (user[i].type == -1)
				{//找出尚未确定type的顶点,重复BFS
					user[i].type = 1;
					q.push(i);
					sum++;
					break;
				}
			}
		}
	}
	vector<int> type1(0), type2(0);
	//把顶点分为两类
	for (int i = 0; i < user.size(); i++)
	{
		if (user[i].type == 0)
			type1.push_back(i);
		else
			type2.push_back(i);
	}
	int maxMatch = 0;
	for (auto x : type1)//(int x = 0; x < user.size();x++)//
	{//只遍历一边的用户

		//记录顶点x在匹配时,已经被访问过的顶点,在下一个顶点匹配时,visited会清零
		vector<bool> visited(user.size(), false);
		if (isMatch(x,visited,user))
			maxMatch++;
	}
	cout << maxMatch << endl;
	return 0;
}


版本二,只有访问数组:

//#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;

/*
5 4
3 2
1 3
5 4
1 5

6 5
3 2
1 3
5 4
1 5
4 6
*/
struct UserNode{
	vector<int> list;//user的邻居
	int type;//user类型
	int from;//与user匹配的点 from--->user
	UserNode() :list(0), type(-1),from(-1){};
};
bool isMatch(int x, vector<bool>& visited, vector<UserNode>& user)
{
	for (auto neighbor:user[x].list)
	{//访问x的邻居
		if (!visited[neighbor])
		{//该邻居之前没有被访问,已被访问的证明已经进行了调整,不再访问遍历
			visited[neighbor] = true;
			if (user[neighbor].from == -1 || isMatch(user[neighbor].from,visited,user))
			{//如果邻居还没有被匹配,或者邻居原来的匹配点from可以有新的匹配
				user[neighbor].from = x;//把x与该邻居匹配
				return true;
			}
		}
	}
	//遍历了x的所有邻居后,发现不能匹配,则false
	return false;
}
int main(void) {

	int n, m;
	cin >> n >> m;
	if (n == 0)
	{
		cout << 0 << endl;
		return 0;
	}
	vector<UserNode> user(n);
	for (int i = 0; i < m; i++)
	{//输入边
		int a, b;
		scanf("%d %d", &a, &b);
		a--; b--;
		//构建图
		user[a].list.push_back(b);
		user[b].list.push_back(a);
	}

	int maxMatch = 0;
	for (int x = 0; x < user.size();x++)//(auto x : type1)
	{//只遍历一边的用户

		//记录顶点x在匹配时,已经被访问过的顶点,在下一个顶点匹配时,visited会清零
		vector<bool> visited(user.size(), false);
		if (isMatch(x,visited,user))
			maxMatch++;
	}
	cout << maxMatch/2 << endl;
	return 0;
}


1066. Root of AVL Tree (25)

1.题目给出一个数组,要求逐个输入后,输出AVL树的根。

2.这道题比较重要,主要考察AVL树的建立。

3.需要掌握单旋转,双旋转,插入等操作。

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

An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.

1066

Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (<=20) which is the total number of keys to be inserted. Then N distinct 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, print ythe root of the resulting AVL tree in one line.

Sample Input 1:

5
88 70 61 96 120

Sample Output 1:

70

Sample Input 2:

7
88 70 61 96 120 90 65

Sample Output 2:

88

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;
/*
5
88 70 61 96 120

7
88 70 61 96 120 95 65
*/
struct AvlNode{
	int val, height;
	AvlNode*l, *r;
	AvlNode() :val(-1), height(-1), l(NULL), r(NULL){};
	AvlNode(int x) :val(x), height(0), l(NULL), r(NULL){};
};
static int Height(AvlNode* T)
{
	if (T == NULL) return -1;
	else return T->height;
}
static AvlNode* SingleRotateLeft(AvlNode* k2)
{
	AvlNode*k1 = k2->l;
	k2->l = k1->r;
	k1->r = k2;
	k2->height = max(Height(k2->l), Height(k2->r)) + 1;
	k1->height = max(Height(k1->l), k2->height) + 1;
	return k1;
}
static AvlNode* SingleRotateRight(AvlNode* k1)
{
	AvlNode*k2 = k1->r;
	k1->r = k2->l;
	k2->l = k1;
	k1->height = max(Height(k1->l), Height(k1->r)) + 1;
	k2->height = max(Height(k2->r), k1->height) + 1;
	return k2;
}
static AvlNode* DoubleRotateLeft(AvlNode* k3)
{
	k3->l = SingleRotateRight(k3->l);
	return SingleRotateLeft(k3);
}

static AvlNode* DoubleRotateRight(AvlNode* k3)
{
	k3->r = SingleRotateLeft(k3->r);
	return SingleRotateRight(k3);
}

static AvlNode* Insert(int x, AvlNode*T)
{
	if (T == NULL)
		T = new AvlNode(x);
	else if (x < T->val)
	{
		T->l = Insert(x, T->l);
		if (Height(T->l) - Height(T->r) == 2)
		{
			if (x < T->l->val)
				T = SingleRotateLeft(T);
			else
				T = DoubleRotateLeft(T);
		}
	}
	else if (x > T->val)
	{
		T->r = Insert(x, T->r);
		if (Height(T->r) - Height(T->l) == 2)
		{
			if (x>T->r->val)
				T = SingleRotateRight(T);
			else
				T = DoubleRotateRight(T);
		}
	}
	T->height = max(Height(T->l), Height(T->r)) + 1;
	return T;
}
int main(void)
{
	int n;
	cin >> n;
	AvlNode* root = NULL;
	for (int i = 0; i < n; i++)
	{
		int tmp;
		cin >> tmp;
		root=Insert(tmp, root);
	}
	cout << root->val << endl;
	return 0;
}

1065. A+B and C (64bit) (20)

1.题目给出三个数a,b,c,要求判断a+b是否等于c。

2.使用string读取a和b,如果符号相同,按照字符串来处理,因为两个负数或者两个正数相加,会超过最大的取值范围。

3.如果符号不同,那么a+b一定会在范围内,可以使用long long进行处理和比。

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

Given three integers A, B and C in [-263, 263], you are supposed to tell whether A+B > C.

Input Specification:

The first line of the input gives the positive number of test cases, T (<=10). Then T test cases follow, each consists of a single line containing three integers A, B and C, separated by single spaces.

Output Specification:

For each test case, output in one line “Case #X: true” if A+B>C, or “Case #X: false” otherwise, where X is the case number (starting from 1).

Sample Input:

3
1 2 3
2 3 4
9223372036854775807 -9223372036854775808 0

Sample Output:

Case #1: false
Case #2: true
Case #3: false

 
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;
/*
1000
9223372036854775807 -9223372036854775808 0
9223372036854775807 -9223372036854775806 0
9223372036854775808 -9223372036854775807 1
9223372036854775808 -9223372036854775807 2
1 1 0
1 1 2
1 1 3
-1 -1 0
-1 -1 -2
-1 -1 -3
*/
long long str2long(string a)
{
	long long ans = 0;
	for (int i = 0; i < a.size(); i++)
		ans = ans * 10 + a[i] - '0';
	return ans;
}
string reverseStr(string a)
{
	for (int i = 0; i < a.size() / 2; i++)
		swap(a[i], a[a.size() - 1 - i]);
	return a;
}

int main(void)
{
	int n;
	cin >> n;
	for (int k = 0; k < n;k++)
	{
		bool isBigger = true;
		string a, b;
		cin >> a >> b;
		bool aPositive = false;
		bool bPositive = false;
		//如果是负数,则进行标记和去掉负号
		if (a[0] == '-')
		{
			a = a.substr(1);
			aPositive = true;
		}
		if (b[0] == '-')
		{
			b = b.substr(1);
			bPositive = true;
		}
		if ((aPositive&&bPositive) || (!aPositive&&!bPositive))
		{
			string ans = "";
			if (a.size() > b.size()) swap(a, b);//保证a最短
			a = reverseStr(a);
			b = reverseStr(b);
			int i = 0;
			int carry = 0;
			for (; i < a.size(); i++)
			{
				int sum = a[i] - '0' + b[i] - '0' + carry;
				carry = sum / 10;
				char c = sum % 10 + '0';
				ans = c + ans;
			}

			for (; i < b.size(); i++)
			{
				int sum = b[i] - '0' + carry;
				carry = sum / 10;
				char c = sum % 10 + '0';
				ans = c + ans;
			}
			if (carry != 0)
			{
				char c = carry + '0';
				ans = c + ans;
			}
			
			//输入c
			string c;
			cin >> c;
			bool cPositive = false;
			if (c[0] == '-')
			{
				c = c.substr(1);
				cPositive = true;
			}
			if (aPositive&&bPositive && cPositive)
			{//a+b为负数,c为负数
				if (ans.size() > c.size())//a+b的绝对值大于c的绝对值
					isBigger = false;
				else if (ans.size() == c.size())
				{
					for (int i = 0; i < ans.size(); i++)
					{
						if (ans[i]>c[i])
						{//a+b的绝对值大于c的绝对值
							isBigger = false;
							break;
						}
						else if (ans[i] < c[i])
						{//a+b的绝对值小于c的绝对值
							isBigger = true;
							break;
						}
					}
					if (ans == c) isBigger = false;//相等的话,为false
				}
				else
					isBigger = true;
			}
			else if (aPositive&&bPositive && !cPositive)
			{//a+b为负数,c为正数
				isBigger = false;
			}
			else if (!aPositive&&!bPositive && cPositive)
			{//a+b为正数,c为负数
				isBigger = true;
			}
			else
			{//a+b为正数,c为正数
				if (ans.size() > c.size())//a+b的绝对值大于c的绝对值
					isBigger = true;
				else if (ans.size() == c.size())
				{
					for (int i = 0; i < ans.size(); i++)
					{
						if (ans[i]>c[i])
						{//a+b的绝对值大于c的绝对值
							isBigger = true;
							break;
						}
						else if (ans[i] < c[i])
						{//a+b的绝对值小于c的绝对值
							isBigger = false;
							break;
						}
					}
					if (ans == c) isBigger = false;//相等的话,为false
				}
				else
					isBigger = false;
			}
		}
		else
		{
			long long aInt = str2long(a), bInt = str2long(b);
			long long ans;
			if (!aPositive&&bPositive)
				ans = aInt - bInt;
			else
				ans = bInt - aInt;
			long long c;
			cin >> c;
			if (ans > c)
				isBigger = true;
			else isBigger = false;
		}

		if (isBigger)
			printf("Case #%d: true\n", k + 1);
		else
			printf("Case #%d: false\n", k + 1);
	}
	return 0;
}

1064. Complete Binary Search Tree (30)

1.题目给出一个数组,要求构成完全的BST。

2.建立一个n节点的 完全二叉树,然后使用中序遍历,把地址数组遍历出来,再填充数组。

3.注意读取的数组需要先排序,在填充到完全二叉树的中序遍历数组中。

1064

时间限制
100 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.

A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.

Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.

Input Specification:

Each input file contains one test case. For each case, the first line contains a positive integer N (<=1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.

Output Specification:

For each test case, print in one line the level order traversal sequence of the corresponding complete binary search 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:

10
1 2 3 4 5 6 7 8 9 0

Sample Output:

6 3 8 1 5 7 9 0 2 4

 
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;
struct TreeNode{
	int val;
	TreeNode*l, *r;
	TreeNode() :val(-1), l(NULL), r(NULL){};
};
void inOrder(TreeNode*root, vector<TreeNode*>&ans)
{
	if (root != NULL)
	{
		inOrder(root->l, ans);
		ans.push_back(root);
		inOrder(root->r, ans);
	}
}
int main(void)
{
	int n;
	cin >> n;
	if (n == 0)
	{
		cout << endl;
		return 0;
	}
	vector<TreeNode> tree(n);
	queue<TreeNode*> q;
	int idx = 0;
	q.push(&tree[idx++]);
	int count1 = 1;
	int count2 = 0;
	//建立一棵节点数为n的完全二叉树
	while (idx < n)
	{
		for (int i = 0; i < count1; i++)
		{
			TreeNode*head = q.front();
			q.pop();
			head->l = &tree[idx++];
			q.push(head->l);
			count2++;
			if (idx == n)
				break;
			head->r = &tree[idx++];
			q.push(head->r);
			count2++;
			if (idx == n)
				break;
		}
		count1 = count2;
		count2 = 0;
	}

	//把树按照中序遍历出一个数组,然后填充数值,主要读取的数组要先排序
	vector<TreeNode*> in(0);
	inOrder(&tree[0], in);
	vector<int> num(n);
	for (int i = 0; i < in.size(); i++)
	{
		scanf("%d", &num[i]);
	}
	sort(num.begin(), num.end());
	for (int i = 0; i < in.size(); i++)
	{
		in[i]->val = num[i];
	}

	queue<TreeNode*> bfs;
	bfs.push(&tree[0]);
	count1 = 1;
	count2 = 0;
	vector<int> ans(0);
	int idxOut = 0;
	while (!bfs.empty())
	{
		for (int i = 0; i < count1; i++)
		{
			TreeNode*head = bfs.front();
			bfs.pop();
			if (idxOut == 0)
				printf("%d", head->val);
			else
				printf(" %d", head->val);
			idxOut++;
			if (head->l != NULL)
			{
				bfs.push(head->l);
				count2++;
			}
			if (head->r != NULL)
			{
				bfs.push(head->r);
				count2++;
			}
		}
		count1 = count2;
		count2 = 0;
	}
	

	return 0;
}