九度OJ题目1000--1049解题练习(二)

题目1000:计算a+b

题目描述:

求整数a,b的和。

输入:

测试案例有多行,每行为a,b的值。

方法:

很简单,直接输出

输出:

输出多行,对应a+b的结果。

样例输入:
1 2
4 5
6 9

样例输出:

3
9
15

程序实现如下:

#include <iostream>
using namespace std;
int main() 
{
    int a,b;
    while (cin >> a >> b) 
   {
        cout << a+b << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1000
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/

题目1001:A+B for Matrices


题目描述:

    This time, you are supposed to find A+B where A and B are two matrices, and then count the number of zero rows and columns.

输入:

    The input consists of several test cases, each starts with a pair of positive integers M and N (≤10) which are the number of rows and columns of the matrices, respectively. Then 2*M lines follow, each contains N integers in [-100, 100], separated by a space. The first M lines correspond to the elements of A and the second M lines to that of B.

    The input is terminated by a zero M and that case must NOT be processed.

输出:

    For each test case you should output in one line the total number of zero rows and columns of A+B.

样例输入:
2 2
1 1
1 1
-1 -1
10 9
2 3
1 2 3
4 5 6
-1 -2 -3
-4 -5 -6
0
样例输出:
1
5

#include <iostream>
using namespace std;
 
int getArrZero(int **arr1, int **arr2, int row,int col);
int main()
{
    int nRow = 0, nCol = 0;
    while (cin >> nRow )
    {
        if (nRow == 0)
        {
            break;
        }
        cin >> nCol;
        //准备接收两个指定规模的二维数据,申请数据
        int **Arr1;
        Arr1 = new int *[nRow];
        for (int i = 0; i < nRow; i++)
        {
            Arr1[i] = new int[nCol];
        }
        int **Arr2;
        Arr2 = new int *[nRow];
        for (int i = 0; i < nRow; i++)
        {
            Arr2[i] = new int[nCol];
        }
 
        //获取两个矩阵的数据
        for (int i = 0; i < nRow; i++)
        {
            for (int j = 0; j < nCol; j++)
            {
                cin >> Arr1[i][j];
            }
        }
 
        for (int i = 0; i < nRow; i++)
        {
            for (int j = 0; j < nCol; j++)
            {
                cin >> Arr2[i][j];
            }
        }
 
        //获得行或者列的零总数
        int count = getArrZero(Arr1,Arr2,nRow,nCol);
        cout << count << endl;
 
        //释放内纯
        for (int i = 0; i < nRow; i++)
        {
            delete[] Arr1[i], Arr2[i];
            Arr1[i] = NULL,Arr2[i] = NULL;
        }
        delete[] Arr1, Arr2;
        Arr1 = NULL,Arr2 = NULL;
    }
    return 0;
}
 
int getArrZero(int **arr1, int **arr2, int row, int col)
{
    int count = 0;
    int **Arr;
    Arr = new int *[row];
    for (int i = 0; i < row; i++)
    {
        Arr[i] = new int[col];
    }
    int jj = 0;
    for (int i = 0; i < row;i++)//行
    {
        for (int j = 0; j < col;j++)//列
        {
            Arr[i][j] = arr1[i][j] + arr2[i][j];//计算结果
        }
        for (jj = 0; jj < col; jj++)//判断某一行是否全是0
        {
            if (Arr[i][jj])//一旦不是0就跳出,下一个if判断将不被执行
            {
                break;
            }
        }
        if (jj==col)
        {
            count++;
        }
    }
 
    for (int i = 0; i < col;i++)
    {
        for (jj = 0; jj < row;jj++)
        {
            if (Arr[jj][i])
            {
                break;
            }
        }
        if (jj == row)
        {
            count++;
        }
    }
 
    //释放内存
    for (int i = 0; i < row; i++)
    {
        delete[] Arr[i];
        Arr[i] = NULL;
    }
    delete[] Arr;
    Arr = NULL;
 
    return count;
}
/**************************************************************
    Problem: 1001
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/


题目1002:Grading


题目描述:

    Grading hundreds of thousands of Graduate Entrance Exams is a hard work. It is even harder to design a process to make the results as fair as possible. One way is to assign each exam problem to 3 independent experts. If they do not agree to each other, a judge is invited to make the final decision. Now you are asked to write a program to help this process.
    For each problem, there is a full-mark P and a tolerance T(<P) given. The grading rules are:
    • A problem will first be assigned to 2 experts, to obtain G1 and G2. If the difference is within the tolerance, that is, if |G1 - G2| ≤ T, this problem's grade will be the average of G1 and G2.
    • If the difference exceeds T, the 3rd expert will give G3.
    • If G3 is within the tolerance with either G1 or G2, but NOT both, then this problem's grade will be the average of G3 and the closest grade.
    • If G3 is within the tolerance with both G1 and G2, then this problem's grade will be the maximum of the three grades.
    • If G3 is within the tolerance with neither G1 nor G2, a judge will give the final grade GJ.

输入:

    Each input file may contain more than one test case.
    Each case occupies a line containing six positive integers: P, T, G1, G2, G3, and GJ, as described in the problem. It is guaranteed that all the grades are valid, that is, in the interval [0, P].

输出:

    For each test case you should output the final grade of the problem in a line. The answer must be accurate to 1 decimal place.

样例输入:
20 2 15 13 10 18
样例输出:
14.0

#include <iomanip>//小数点精确
#include <cstdio>  
#include <cstdlib>  
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath> 
 
using namespace std;
//关键在于对异或运算的理解:任何一个数字异或它自己都等于0
int main()
{
    double  P = 0, T = 0, G1 = 0, G2 = 0, G3 = 0, GJ = 0;
    while (cin >> P >> T >> G1 >> G2 >> G3 >> GJ)
    {
        double grade = 0.0;
        // If the difference is within the tolerance, that is,
        //if |G1 - G2| ≤ T, this problem's grade will be the average of G1 and G2.
        if (abs(G1 - G2) <= T)
        {
            grade = (G1 + G2) / 2.0;
        }
        else
        {
            if (abs(G3 - G2) <= T && abs(G3 - G1) > T //如果其中一个在容忍度以内
                || abs(G3 - G2) > T && abs(G3 - G1) <= T)
            {
                if (abs(G3 - G2) > abs(G3 - G1))
                    grade = (G3 + G1) / 2.0;
                else
                    grade = (G3 + G2) / 2.0;
            }
            else if (abs(G3 - G2) <= T && abs(G3 - G1) <= T)//如果都在容忍度以内
                grade = max(max(G1, G2), G3);
            else
                grade = GJ;
        }
        cout <<fixed<<setprecision(1)<< grade << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1002
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/



题目1003:A+B(逗号隔开的数)

题目描述:
给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号","隔开。
现在请计算A+B的结果,并以正常形式输出。

输入:
输入包含多组数据数据,每组数据占一行,由两个整数A和B组成(-10^9 < A,B < 10^9)。

输出:
请计算A+B的结果,并以正常形式输出,每组数据占一行。


方法:
关键是从高位开始,一位一位的翻译成相应的整数
样例输入:
-234,567,890 123,456,789
1,234 2,345,678
样例输出:
-111111101
2346912


C++程序实现如下:

#include <iostream>
#include <string>
using namespace std;
long getBigAns( string &a,  string &b);
 
int main()
{
    string bigNum1, bigNum2;     // 初始状态用string来存储大数
    while (cin >> bigNum1 >> bigNum2)
    {
        if (bigNum1.length() > 12 || bigNum2.length() > 12)
        {
            break;;
        }
        long ans = getBigAns(bigNum1, bigNum2);
        cout << ans << endl;
    }
    return 0;
}
 
long getBigAns(string &a,  string &b)
{
    long a1 = 0, b1 = 0;
    for (unsigned int i = 0; i < a.size();i++)//获取操作数1
    {
        if (a[i] >= '0' && a[i] <= '9')//从高位循环计算出该数
        {
            a1 *= 10;
            a1 += a[i] - '0';
        }
    }
     
    for (unsigned int i = 0; i < b.size(); i++)//获取操作数2
    {
        if (b[i] >= '0' && b[i] <= '9')
        {
            b1 *= 10;
            b1 += b[i] - '0';
        }
    }
 
    //判断符号,计算结果
    if (a[0] == '-' && b[0] == '-')
    {
        return -(a1 + b1);
    }
    else if (a[0] == '-' && b[0] != '-')
    {
        return (b1 - a1);
    }
    else if (a[0] != '-' && b[0] == '-')
    {
        return (a1-b1);
    }
    else
    {
        return a1 + b1;
    }
 
    return -1;//error
}
/**************************************************************
    Problem: 1003
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/


题目1004:Median

题目描述:

    Given an increasing sequence S of N integers, the median is the number at the middle position. For example, the median of S1={11, 12, 13, 14} is 12, and the median of S2={9, 10, 15, 16, 17} is 15. The median of two sequences is defined to be the median of the non-decreasing sequence which contains all the elements of both sequences. For example, the median of S1 and S2 is 13.
    Given two increasing sequences of integers, you are asked to find their median.

输入:

    Each input file may contain more than one test case.
    Each case occupies 2 lines, each gives the information of a sequence. For each sequence, the first positive integer N (≤1000000) is the size of that sequence. Then N integers follow, separated by a space.
    It is guaranteed that all the integers are in the range of long int.

输出:

    For each test case you should output the median of the two given sequences in a line.


方法:

运用归并法重新调整成一个新的数组,在直接根据数组长度求取中间位置的中间值

样例输入:
4 11 12 13 14
5 9 10 15 16 17
样例输出:
13
C++程序实现如下:
#include <iostream>  
using namespace std;
 
#define maxValue 99999
#define max 10001
int getMedian(int *num1,int len1,int *num2,int len2)
{
    int len = len1 + len2;
    int midPos = (len - 1) / 2;
    num1[len1] = maxValue;
    num2[len2] = maxValue;
 
    int *num = new int[len];
    int n = 0, m = 0;
    for (int i = 0; i < len;i++)//由小到大归并
    {
        if (num1[n] >= num2[m])
        {
            num[i] = num2[m];
            m++;
        }
        else
        {
            num[i] = num1[n];
            n++;
        }
    }
 
    int midValue = num[midPos];//直接从归并后的数组中的中间位置获取中间值
    delete[] num;
    num = NULL;
    return midValue;
}
 
int main()
{   
    int len1 = 0;
    int len2 = 0;
    int num1[max] = {0};
    int num2[max] = { 0 };
    while (cin >> len1)
    {
        for (int i = 0; i < len1; i++) //输入数组1
        {
            cin >> num1[i];
        }
        cin >> len2;
        for (int i = 0; i < len2; i++)//输入数组2
        {
            cin >> num2[i];
        }
 
        int mid = getMedian(num1,len1 ,num2,len2);
        cout << mid << endl;
    }
 
    return 0;
}
/**************************************************************
    Problem: 1004
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/

题目1006:ZOJ问题


题目描述:
对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC。

是否AC的规则如下:
1. zoj能AC;
2. 若字符串形式为xzojx,则也能AC,其中x可以是N个'o' 或者为空;
3. 若azbjc 能AC,则azbojac也能AC,其中a,b,c为N个'o'或者为空;
输入:
输入包含多组测试用例,每行有一个只包含'z','o','j'三种字符的字符串,字符串长度小于等于1000。
输出:
对于给定的字符串,如果能AC则请输出字符串“Accepted”,否则请输出“Wrong Answer”。

方法:
总结出规律
样例输入:
zoj
ozojo
ozoojoo
oozoojoooo
zooj
ozojo
oooozojo
zojoooo
样例输出:
Accepted
Accepted
Accepted
Accepted
Accepted
Accepted
Wrong Answer
Wrong Answer
C++程序实现如下:

#include <iostream>
#include "string"
using namespace std;

bool IsAccepted(const string src);
int main()
{
	string str;
	while (cin>>str)
	{
		if (str.length()>1000)
			break;
		if (IsAccepted(str))
			cout << "Accepted" << endl;
		else
			cout << "Wrong Answer" << endl;
		str.erase();
	}
	return 0;
}

bool IsAccepted(const string src)
{
	int zlen = src.find('z');
	int zlast = src.find_last_of('z');//找到z最后一次出现的位置
	if ((zlen-zlast)!=0)//只能出现一个z,否则
		return false;
	int jlen = src.find('j');
	int jlast = src.find_last_of('j');
	if ((jlen - jlast) != 0)//只能出现一个j,否则
		return false;

	int len = src.length();
	int gap = jlen - zlen - 1;

	if (src == "zoj")//情况1
		return true;
	if ((jlen - zlen == 2) && src[(zlen + jlen) / 2] == 'o' 
		&& (zlen == len - 1 - jlen))//情况2
		return true;
	if (zlen * gap == (len-jlen-1) && (gap >= 1))//情况3
		return true;

	return false;
}

题目1008:最短路径问题


题目描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)
输出:
输出 一行有两个数, 最短距离及其花费。
样例输入:
3 2
1 2 5 6
2 3 4 5
1 3
0 0
样例输出:
9 11
C++实现如下:

#include "vector"
#include <iostream>  
using namespace std;
class Edge//边集的定义
{//每条边拥有源起点和目的顶点
public:
    Edge(int dest, int weight, int price)
    {
        m_nposTable = dest;
        m_nWeight = weight;
        m_nPrice = price;
        m_pNext = NULL;
    }
    ~Edge()
    {
    }
private:
    friend class Graph;//将Graph设为友类,允许Graph类任意访问
    friend class Vertex;//将Vertex设为友类,允许Vertex类任意访问
    int m_nposTable;//该边的目的顶点在顶点集中的位置
    int m_nWeight;//边的权重值,即距离
    int m_nPrice;//走这条边的费用
    Edge *m_pNext;//下一条边(注意不是下一个顶点,因为m_nposTable已经知道了这个顶点的位置)
};
 
class Vertex//顶点的定义
{//每一个顶点拥有“名字”和相挨着的邻边
public:
    Vertex()
    {
        padjEdge = NULL;
        m_vertexName = 0;
    }
    ~Vertex()
    {
        Edge *pmove = padjEdge;
        while (pmove)
        {
            padjEdge = pmove->m_pNext;
            delete pmove;
            pmove = padjEdge;
        }
    }
 
private:
    friend class Graph;//将Graph设为友类,允许Graph类任意访问
    int m_vertexName;//顶点“名字”
    Edge *padjEdge;//顶点的邻边
 
};
 
class Graph
{
public:
    Graph(int size )
    {
        m_pVertexTable = new Vertex[size];  //为顶点集分配内存
        m_numVertexs = size;
        m_Infinity = 100000860;
        for (int i = 0; i < size;i++)
            m_pVertexTable[i].m_vertexName = i+1;
    }
 
    ~Graph()
    {
        Edge *pmove;
        for (int i = 0; i < this->m_numVertexs; i++)
        {
            pmove = this->m_pVertexTable[i].padjEdge;
            if (pmove){
                this->m_pVertexTable[i].padjEdge = pmove->m_pNext;
                delete pmove;
                pmove = this->m_pVertexTable[i].padjEdge;
            }
        }
        delete[] m_pVertexTable;
    }
    //在顶点集中位置为v1和v2的顶点之间插入边
    bool InsertEdge(int v1, int v2, int weight, int price = 0);
    //插入顶点名字为vertex的顶点
    bool InsertVertex(const int vertex);
    //顶点v到其他各个顶点的最短路径(包括自身)
    void Dijkstra(int v, vector<int> &shPath, vector<int> &cost);
    //获取顶点集中位置为v1和v2的顶点之间边的权重值
    int GetWeight(int v1, int v2, bool IsFee=false);
     
private:
    Vertex *m_pVertexTable;   //顶点集
    int m_numVertexs;//图中当前的顶点数量
    int m_Infinity;  //边的默认权值(可以看成是无穷大)
};
 
 
//返回顶点v1和v2之间的边权值,
//如果没有直接相连(即不是一条边直接相连)则返回无穷大
 
int Graph::GetWeight(int v1, int v2,bool IsFee)
{
    if (v1 == v2)
        return 0;
    Edge *pmove = m_pVertexTable[v1].padjEdge;
    while (pmove)
    {
        if (pmove->m_nposTable == v2)
            if (IsFee)
                return pmove->m_nPrice;
            else
                return pmove->m_nWeight;
        pmove = pmove->m_pNext;
    }
    return m_Infinity;
}
 
//在顶点集位置为v1和v2的顶点之间插入权值为weght和费用为price的边
bool Graph::InsertEdge(int v1, int v2, int weight,int price)
{
    Edge *pmove = m_pVertexTable[v1].padjEdge;
    if (pmove == NULL)//如果顶点v1没有邻边
    { //建立顶点v1的第一个邻边(该邻边指明了目的顶点)
        m_pVertexTable[v1].padjEdge = new Edge(v2, weight, price);
        return true;
    }
    else//如果有邻边
    {
        while (pmove->m_pNext)
        {
            pmove = pmove->m_pNext;
        }
        pmove->m_pNext = new Edge(v2, weight, price);
        return true;
    }
}
 
//Dijkstra单源最短路径算法
void Graph::Dijkstra(int v, vector<int> &shPath, vector<int> &cost)
{
    vector<int> visited(m_numVertexs, 0);
    for (int i = 0; i < m_numVertexs; i++)
    {   //初始化
        shPath[i] = this->GetWeight(v, i);//顶点v(当前搜索点)到各个相邻顶点的边距离,其他情况返回无穷大
        cost[i] = this->GetWeight(v, i,true);//顶点v(当前搜索点)到各个相邻顶点的费用,其他情况返回无穷大
    }
 
    visited[v] = 1;//第v个顶点初始化为被访问,并以他为当前搜索点开始找最短路径
 
    for (int i = 1; i < m_numVertexs; i++)
    {
        int min = this->m_Infinity;
        int u = 0;
 
        //寻找新的搜索点u,依据就是数组中权值最小的那个点的位置(且没被访问过)
        for (int j = 0; j < m_numVertexs; j++)
        {
            if (!visited[j] && shPath[j] < min)
            {
                    min = shPath[j];//获得当前shPath数组中的最小边权重
                    u = j;//用u来记录获取最小值时的顶点位置,即新的搜索点
            }
        }
        visited[u] = 1;//已经确定的最短路径
        //以u为搜索点寻找顶点v到顶点w的最短路径
        for (int w = 0; w < m_numVertexs; w++)
        {
            int weight = this->GetWeight(u, w);//顶点u(当前搜索点)到各个相邻顶点的边权值,其他情况返回无穷大
            int price = this->GetWeight(u, w, true);
            if (!visited[w] && weight != this->m_Infinity)
            {
                if (shPath[u] + weight < shPath[w])
                {
                    shPath[w] = shPath[u] + weight;//更新顶点v到w的最短路径值
                    cost[w] = cost[u] + price;
                }
                else if (shPath[u] + weight == shPath[w])
                {
                    if (cost[u] + price < cost[w])
                    {
                        shPath[w] = shPath[u] + weight;//更新顶点v到w的最短路径值
                        cost[w] = cost[u] + price;
                    }
                }
            }
        }
    }
}
 
int main()
{
    //务必保持输入的准确性,否则.....很严重
    int n = 0, m = 0;
    while (cin >> n >> m)
    {
        if (n == 0 && m == 0)
            break;
        if (n <= 1 || n > 1000 || m <= 0 || m >= 100000)
            break;
        Graph graph(n);//创建n个顶点,并且已经初始化顶点
        //获取边的属性
        int a = 0, b = 0, d = 0, p = 0;
        int s = 0, t = 0;
        while (m--)
        {
            cin >> a >> b >> d >> p;
            graph.InsertEdge(a-1, b-1, d, p);
            graph.InsertEdge(b-1, a-1, d, p);
        }
        cin >> s >> t;
        if (s == t)
            break;
        vector<int> shortestPath(n,0);//存储Dijkstra算法最短路径值  
        vector<int> fee(n,0);//存储Dijkstra算法最短路径值 
        graph.Dijkstra(s-1, shortestPath,fee);
        cout << shortestPath[t - 1] << " " << fee[t - 1] << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1008
    User: EbowTang
    Language: C++
    Result: Wrong Answer
****************************************************************/

题目1009:二叉搜索树

题目描述:
判断两序列是否为同一二叉搜索树序列
输入:
开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束。
接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树。
接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树。
输出:

如果序列相同则输出YES,否则输出NO

样例输入:
2
567432
543267
576342
0
样例输出:
YES
NO
#include <iostream>
#include "string"
using namespace std;
 
string strTree;
 
typedef struct _BSTreeNode//二叉树节点
{
        char value;
        struct _BSTreeNode *left;
        struct _BSTreeNode *right;
} BSTreeNode;
 
void BuildTree(char c, BSTreeNode *pCurNode)//建立树
{
    if (pCurNode == NULL)//新节点,那就是根节点了
     {
        pCurNode = new BSTreeNode;
        pCurNode->value = c;
        pCurNode->left = NULL;
        pCurNode->right = NULL;
     }
     else
     {
        if (c < pCurNode->value)
            BuildTree(c, pCurNode->left);
        else if (c > pCurNode->value)
            BuildTree(c, pCurNode->right);
        else
            cout << "Value Exist!!!" << endl;
     }
         
}
 
//判断树中的每个相应位置的节点是否相等
bool IsEqual(BSTreeNode *pTreeNode1, BSTreeNode *pTreeNode2)
{
    if (pTreeNode1 == NULL && pTreeNode2 == NULL)//两棵树都是空的,则相同
         return true;
    else if (pTreeNode1 == NULL && pTreeNode2 != NULL)//某一边无值,显然不同
         return false;
    else if (pTreeNode1 != NULL && pTreeNode2 == NULL)
         return false;
    else//两边都有值,就看是否相等,
    {
            if (pTreeNode1->value != pTreeNode2->value)//显然不同,即可返回
                return false;
            else
                return (IsEqual(pTreeNode1->left, pTreeNode2->left) && IsEqual(pTreeNode1->right, pTreeNode2->right));
    }
}
 
int main()
{
        int n = 0;
        while (cin >> n)
        {
                if (n == 0)
                   break;
                //重建第一棵树
                cin >> strTree;
                BSTreeNode *pTree1 = NULL;
                for (int i = 0; strTree.size(); i++)
                    BuildTree(strTree[i], pTree1);    
                strTree.erase();
 
                for (int i=0; i < n; i++)
                {
                    //重建第二棵树
                    cin >> strTree;
                    BSTreeNode *pTree2 = NULL;
                    for (int i = 0; strTree.size(); i++)
                        BuildTree(strTree[i], pTree2);
                    //判断是否一样
                    if (IsEqual(pTree1, pTree2))
                        cout << "YES" << endl;
                    else
                        cout << "NO" << endl;
                    strTree.erase();
                }
        }
        return 0;
}
/**************************************************************
    Problem: 1009
    User: EbowTang
    Language: C++
    Result: Memory Limit Exceed
****************************************************************/


题目1010:A + B

题目描述:
读入两个小于100的正整数A和B,计算A+B.
需要注意的是:A和B的每一位数字由对应的英文单词给出.
输入:
测试输入包含若干测试用例,每个测试用例占一行,格式为"A + B =",相邻两字符串有一个空格间隔.当A和B同时为0时输入结束,相应的结果不要输出.
输出:
对每个测试用例输出1行,即A+B的值.

方法:
利用stl中的string类
首先寻找+号前的子串,然后求取其对应的操作数(首先寻找空格是否存在,若不存在就好办了,若不存在重新求子串再求取对应的位数)
然后同理求取+号后的子串,求取其对应的操作数(同上)
样例输入:
one + two =
three four + five six =
zero seven + eight nine =
zero + zero =
样例输出:
3
90
96
C++程序实现如下:

#include <fstream>  
#include <string>  
#include <iostream>  
using namespace std;
 
string base[] = { "zero", "one", "two", "three", "four", "five","six", "seven", "eight", "nine" };
 
int getOperator(string op)
{
    int result = 0;
    string a, b;
    int j = op.find(" ");
 
    if (j == -1)//如果op没有空格就返回-1
    {
        for (int i = 0; i < 10; i++)
        {
            if (op == base[i])
                return result += i;
        }
    }
    else//如果有空格,获得其位置,此时将会是两位数
    {
        a = op.substr(0, j);//获得空格之前的子串
        b = op.substr(j + 1, op.length() - j - 1);//获得空格之后的子串
 
        for (int i = 0; i < 10; i++)
        {
            if (a == base[i])//获取十位
                result = 10 * i;
        }
        for (int i = 0; i < 10; i++)
        {
            if (b == base[i])//获取个位
                return result += i;
        }
    }
    return -1;//error
}
 
int main()
{   
    string src, sub1, sub2;
    char add = '+';
    while (getline(cin, src))//获取整行输入,此处不能用cin>>s,因为遇到空格不再接受
    {
        //"one + two ="
        int idx = src.find(add);//获取+号第一次出现的位置
        sub1 = src.substr(0, idx - 1);//寻找+前面的子串,注意从0位置起到后面idx-1都是要获取的子串
        sub2 = src.substr(idx + 2, src.length() - idx - 4);//+号后面的子串
        int ans = getOperator(sub1) + getOperator(sub2);
        if (ans)//如果为0就不输出
        {
            cout << ans << endl;
        }
        src.erase();
    }
    return 0;
}
/**************************************************************
    Problem: 1010
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/


题目1011:最大连续子序列

题目描述:

    给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。现在增加一个要求,即还需要输出该子序列的第一个和最后一个元素。
输入:

    测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K< 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。

输出:

    对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

样例输入:
6
-2 11 -4 13 -5 -2
10
-10 1 2 3 4 -5 -23 3 7 -21
6
5 -8 3 2 5 0
1
10
3
-1 -5 -2
3
-1 0 -2
0
样例输出:
20 11 13
10 1 4
10 3 5
10 10 10
0 -1 -2
0 0 0
<span style="font-size:12px;">#include <iostream>
#include "vector"
using namespace std;
int getMaxSubArr(vector<int> &v, vector<int> &a);
int getMax(int a, int b);
int main()
{
    int k = 0;
    while (cin>>k)
    {
        if (k == 0)
            break;
        vector<int> vec(k,0);
        for (int i = 0; i < k;i++)
            cin >> vec[i];
         
        vector<int> ans(3,0);//用于获取答案
        getMaxSubArr(vec, ans);
 
        cout << ans[0];
        for (int i = 1; i < 3;i++)
            cout <<" "<<ans[i];
    }
    return 0;
}
 
int getMax(int a, int b)
{
    if (a>b)
        return a;
    else
        return b;
}
int getMaxSubArr(vector<int> &v, vector<int> &a)
{
    if (v.size()==0)
        return -1;//error
     
    vector<int> tempSum(v.size(), 0);//tempSum[i]只与vec[i]有关,对vec[i]进行累加 
    tempSum[0] = v[0];
    vector<int>  maxSum(v.size(), 0);//maxSum[i]表示a[0]到a[i]的最大子段和值  
    maxSum[0] = v[0];//当只有一元素时的最大连续子段和  
    a[1] = v[0];
    unsigned int i = 1;
    for (; i < v.size(); i++)
    {//状态转移//如果tempSum[i - 1] + vec[i]小,说明tempsum起副作用了(小于0了),重新以当前元素vec[i]开始累加  
        tempSum[i] = getMax(tempSum[i - 1] + v[i],v[i]);
        if (tempSum[i - 1] + v[i] < v[i])
            a[1] = v[i];
        maxSum[i] = getMax(maxSum[i - 1], tempSum[i]);//更新a[0]到a[i]的最大子段和值   
        if (maxSum[i - 1] < tempSum[i])
            a[2] = v[i];
    }
 
    a[0]= maxSum[i - 1];
    return 1;
}
/**************************************************************
    Problem: 1011
    User: EbowTang
    Language: C++
    Result: Wrong Answer
****************************************************************/</span>


题目1012:畅通工程

题目描述:

    某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

输入:

    测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
    注意:两个城市之间可以有多条道路相通,也就是说
    3 3
    1 2
    1 2
    2 1
    这种输入也是合法的
    当N为0时,输入结束,该用例不被处理。

输出:

    对每个测试用例,在1行里输出最少还需要建设的道路数目。

样例输入:
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0
样例输出:
1
0
2
998

#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
 
class UFSet
{
public:
    UFSet(int nsize)
    {
        size = nsize;
        parent = new int[size];
    };
    ~UFSet()
    {
        delete[] parent;
        parent = NULL;
    };
    void makeSet(int n);////初始化每个元素的祖先为自身
    int findSet(int x);//找到元素x的祖先元素parent[x]
    void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先
    int getSets(int n);//获取独立的集合数量
private:
    int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x
    int size;
};
 
void UFSet::makeSet(int n) //初始化
{
    //初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身
    for (size_t i = 1; i <= n; i++)
        parent[i] = i;
}
 
int UFSet::findSet(int x)
{
    //找到元素所在的集合,也就是找到自己的最高的祖先,
    //这也是判断两个元素是否在同一个集合中的主要依据。
    if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
        return x;
 
    parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先
    return parent[x];
}
 
void UFSet::unionSet(int x, int y)
{
    //将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,
    //如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。
    int ux = findSet(x);//获取节点x的祖先
    int uy = findSet(y);
    if (ux != uy)
        parent[ux] = uy;
}
 
 
int UFSet::getSets(int n)
{
    int count = 0;
    for (int i = 1; i <= n; i++)
    {//如果存在某一个节点的祖先是自身说明他是孤立的
        if (parent[i] == i)
            count++;
    }
    return count;
}
 
int main()
{
    int m, n;
    while (cin >> n >> m)
    {
        UFSet uset(10000);
        uset.makeSet(n);//初始化
        //接收m对已经联通的城镇
        int x = 0, y = 0;
        for (int i = 0; i<m; i++)
        {
            cin >> x >> y;//注:这里数组下标位置代表城镇编号
            uset.unionSet(x, y);
        }
        cout << uset.getSets(n)-1 << endl;
 
    }
    return 0;
}
/**************************************************************
    Problem: 1012
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/


题目1015:还是A+B

题目描述:
读入两个小于10000的正整数A和B,计算A+B。需要注意的是:如果A和B的末尾K(不超过8)位数字相同,请直接输出-1。
输入:

测试输入包含若干测试用例,每个测试用例占一行,格式为"A B K",相邻两数字有一个空格间隔。当A和B同时为0时输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即A+B的值或者是-1。

样例输入:
1 2 1
11 21 1
108 8 2
36 64 3
0 0 1
样例输出:
3
-1
-1
100
#include <iostream>
#include "string"
#include "vector"
using namespace std;
 
int getAnswer(const string &s1,const string &s2,int k);
int getOper(const string &s1);
int main()
{
    string s1, s2;
    while (cin>>s1,cin>>s2)//注意cin不接受空格
    {
        if (s1.size() == 1 && s1 == "0"&&s2.size() == 1 && s2 == "0")
            break;
         
        int k = 0;
        cin >> k;
        cout << getAnswer(s1, s2, k) << endl;
    }
    return 0;
}
 
int getOper(const string &s1)//将字符翻译成对应数字
{
    int ans = 0;
    for (unsigned int i = 0; i < s1.size();i++)
    {
        ans *= 10;
        ans += s1[i] - '0';
    }
    return ans;
}
int getAnswer(const string &s1, const string &s2,int k)
{   
    int i = 0;
    for (; i < k;i++){
        if (s1[s1.size() - 1 - i] != s2[s2.size() - 1 - i])
            break;
    }
    if (i==k)
        return -1;
    else
        return getOper(s1) + getOper(s2);
}
/**************************************************************
    Problem: 1015
    User: EbowTang
    Language: C++
    Result: Wrong Answer
****************************************************************/


题目1017:还是畅通工程

题目描述:
    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
输入:

    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。

输出:

    对每个测试用例,在1行里输出最小的公路总长度。

样例输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
样例输出:
3
5
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
class Edge
{
public:
    int acity;//城市a
    int bcity;//城市b
    int cost;  //建成a到b的路的花费
    bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。
    {  
        return cost<q.cost;
    }
};
 
Edge edge[10000];
 
class UFSet
{
public:
    UFSet(int nsize)
    {
        size = nsize;
        parent = new int[size+1];
    };
    ~UFSet()
    {
        delete[] parent;
        parent = NULL;
    };
    void makeSet(int n);////初始化每个元素的祖先  
    int findSet(int x);//找到元素x的祖先元素  
    void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先  
    int getMinCost(int m);//获取最小花费 
private:
    int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x  
    int size;
};
 
void UFSet::makeSet(int n) //初始化  
{
    //初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身  
    for (size_t i = 1; i <= n; i++)
        parent[i] = i;
}
 
int UFSet::findSet(int x)
{
    //找到元素所在的集合,也就是找到自己的最高的祖先,  
    //这也是判断两个元素是否在同一个集合中的主要依据。  
    if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
        return x;
 
    parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先  
    return parent[x];
}
 
void UFSet::unionSet(int x, int y)
{
    //将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,  
    //如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。  
    int ux = findSet(x);//获取节点x的祖先  
    int uy = findSet(y);
    if (ux != uy)
        parent[ux] = uy;
}
int UFSet::getMinCost(int m)
{
    sort(edge, edge + m);//必须先对边排序(根据边的修建费用),这样才能贪心的形成最小花费
    int sum = 0;
    for (int i = 0; i<m; i++)
    {
        int baseA = findSet(edge[i].acity);//找到城市a的祖先(要么是自身要么是城市b的编号)
        int baseB = findSet(edge[i].bcity);
        if (baseA != baseB)
        {
            parent[baseA] = baseB;//将城市a的祖先设置成b的祖先这个式子等价于parent[edge[i].acity] = edge[i].bcity
            sum += edge[i].cost;
        }
    }
    return sum;
}
 
int main()
{
    int n = 0;
    while (cin >> n, n > 0)
    {
        int m = n*(n - 1) / 2;
        UFSet uset(10000);
        uset.makeSet(n);//初始化每个城市的祖先为自身
        for (int i = 0; i < m; i++)
            cin>> edge[i].acity>> edge[i].bcity>> edge[i].cost;
        int mincost = uset.getMinCost(m);
        cout << mincost << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1017
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:30 ms
    Memory:1636 kb
****************************************************************/




题目1019:简单计算器

题目描述:
    读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入:
    测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
输出:
    对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
样例输入:
1 + 2
4 + 2 * 5 - 7 / 11
0
样例输出:
3.00
13.36
C++程序实现如下:

#include "string"
#include <iostream>
#include<iomanip>//精确小数点的头文件
#include <stack>
using namespace std;
 
string str;
unsigned int pos;
 
double getNum()
{
    double v = 0;
    for (; pos < str.length(); pos++)
    {
        if (str[pos] > '9' || str[pos] < '0')
        {
            break;
        }
        v *= 10;
        v += str[pos] - '0';
    }
    return 1.0*v;
}
 
int main(int argc, char* argv[])
{
    double a, b;
    double v;
    while (getline(cin,str))
    {
        //"1 + 2"
        if (str.length()>200)
        {
            break;
        }
        stack<double> s;
        pos = 0;
        s.push(getNum());
        if (str.length() == 1 && (str[0] - '0'== 0))
        {
            break;
        }
     
        while (pos < str.length())
        {
            switch (str[pos])
            {
            case '*':
                pos=pos+2;
                a = s.top();
                s.pop();
                b = getNum();
                s.push(a*b);
                break;
            case '/':
                pos=pos+2;
                a = s.top();
                s.pop();
                b = getNum();
                s.push(a / b);
                break;
            case '+':
                pos=pos+2;
                s.push(getNum());
                break;
            case '-':
                pos=pos+2;
                s.push(-1.0*getNum());
                break;
            case ' ':
                pos++;
                break;
            default:
                break;
            }
        }
        v = 0;
        while (!s.empty())
        {
            v += s.top();
            s.pop();
        }
        cout << fixed << setprecision(2) << v << endl;//精确到小数点后两位
    }
    return 0;
}
/**************************************************************
    Problem: 1019
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1524 kb
****************************************************************/

题目1021:统计字符

题目描述:
    统计一个给定字符串中指定的字符出现的次数。
输入:
    测试输入包含若干测试用例,每个测试用例包含2行,第1行为一个长度不超过5的字符串,第2行为一个长度不超过80的字符串。注意这里的字符串包含空格,即空格也可能是要求被统计的字符之一。当读到'#'时输入结束,相应的结果不要输出。
输出:
    对每个测试用例,统计第1行中字符串的每个字符在第2行字符串中出现的次数,按如下格式输出:
    c0 n0
    c1 n1
    c2 n2
    ... 
    其中ci是第1行中第i个字符,ni是ci出现的次数。
样例输入:
I
THIS IS A TEST
i ng
this is a long test string
#
样例输出:
I 2
i 3
  5
n 2
g 2
#include <iostream>
#include "string"
#include "vector"
using namespace std;
 
bool CountChar(const string &s1,const string &s2,vector<int> &vec);
int main()
{
    string s1, s2;
    while (getline(cin,s1))
    {
        if (s1.size() == 1 && s1 == "#")
            break;
        //cin >> s2;//注意,cin不接受空格
        getline(cin, s2);//接收空格
        int nLen = s1.size();
        vector<int> vec(nLen,0);
        CountChar(s1, s2, vec);
        for (int i = 0; i < nLen; i++)
            cout << s1[i] << " " << vec[i] << endl;
    }
    return 0;
}
 
bool CountChar(const string &s1, const string &s2, vector<int> &vec)
{
    for (unsigned int i = 0; i < s1.size(); i++)
    {
        for (unsigned int j = 0; j < s2.size(); j++)
        {
            if (s1[i] == s2[j])
                vec[i]++;
        }
    }
    return true;
}
/**************************************************************
    Problem: 1021
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/



题目1024:畅通工程

题目描述:
    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
输入:
    测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M (N, M < =100 );随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
输出:
    对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
样例输入:
3 3
1 2 1
1 3 2
2 3 4
1 3
2 3 2
0 100
样例输出:
3
?


#include <cstdio>  
#include <ctype.h>
#include <cstdlib>  
#include "queue"
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
 
using namespace std;
 
class Edge
{
public:
    Edge()
    {
        dst = 0;
    }
    int avex;
    int bvex;
    int dst;
    bool operator <(const Edge &mode) const
    {
        return dst<mode.dst;
    }
};
 
Edge edge[1001];
 
class UFSet
{
public:
    UFSet(int nsize)
    {
        parent = new int[nsize+1];
    }
    ~UFSet()
    {
        delete[] parent;
        parent = NULL;
    }
 
    // 初始化每个顶点的祖先为自身
    void makeSet(int n);
 
    // 找到元素x的祖先元素   
    int findSet(int x);
 
    int getMinCost(int m, int n);
 
    int getSets(int n);
private:
    int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x  
     
};
 
void UFSet::makeSet(int n) //初始化      
{
    for (size_t i = 1; i <= n; i++)
        parent[i] = i;
}
 
int UFSet::findSet(int x)
{
 
    if (parent[x] == x)
        return x;
 
    parent[x] = findSet(parent[x]);
    return parent[x];
}
 
 
int UFSet::getMinCost(int nedge, int nvex)
{
    sort(edge + 1, edge + nedge + 1);//必须先对边排序(根据边的修建费用),这样才能贪心的形成最小花费    
    int minCost = 0;
    for (int i = 1; i <= nedge; i++)
    {
        int baseA = findSet(edge[i].avex);
        int baseB = findSet(edge[i].bvex);
        if (baseA != baseB)//在两个集合中,可以选择这条边
        {
            parent[baseA] = baseB;//联合两个顶点 
            minCost += edge[i].dst;                     
        }
    }
 
    if ((nedge + 1) >= nvex && getSets(nvex) == 1)
        cout << minCost << endl;
    else
        cout << "?" << endl;
 
    return minCost;
}
 
int UFSet::getSets(int nvex)
{
    int count = 0;
    for (int i = 1; i <= nvex; i++)
    {//如果存在某一个节点的祖先是自身说明他是孤立的  
        if (parent[i] == i)
            count++;
    }
    return count;
}
 
int main()
{
    int nedge = 0;//边数
    int nvex= 0;//顶点数
    while (cin >> nedge >> nvex)
    {
        if (nedge == 0)
            break;
        UFSet uset(nvex);
        uset.makeSet(nvex);//初始化每个城市的祖先为自身  
        for (int i = 1; i <= nedge; i++)
            scanf("%d%d%d",&edge[i].avex, &edge[i].bvex, &edge[i].dst);
         
        uset.getMinCost(nedge, nvex);
    }
    return 0;
}
/**************************************************************
    Problem: 1024
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1532 kb
****************************************************************/






题目1028:继续畅通工程

题目描述:
    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
输入:
    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

    当N为0时输入结束。
输出:
    每个测试用例的输出占一行,输出全省畅通需要的最低成本。
样例输入:
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
样例输出:
3
1
0
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
class Edge
{
public:
    int acity;//城市a
    int bcity;//城市b
    int cost;  //建成a到b的路的花费
    bool isBuild; //标记路是否建成
    bool operator < (const Edge &q) const//注意返回值的类型,运算符重载。
    {  
        return cost<q.cost;
    }
};
 
Edge edge[10000];
 
class UFSet
{
public:
    UFSet(int nsize)
    {
        size = nsize;
        parent = new int[size+1];
    };
    ~UFSet()
    {
        delete[] parent;
        parent = NULL;
    };
    void makeSet(int n);////初始化每个元素的祖先  
    int findSet(int x);//找到元素x的祖先元素  
    void unionSet(int a, int b);//若两个元素的祖先不同,则将x元素的祖先设置为y元素的祖先  
    int getMinCost(int m);//获取最小花费 
private:
    int *parent;//存放祖先节点,例如x=parent[i],元素i的祖先节点为元素x  
    int size;
};
 
void UFSet::makeSet(int n) //初始化  
{
    //初始化每一个元素都各自为一个独立的集合,其祖先均设定为自身  
    for (size_t i = 1; i <= n; i++)
        parent[i] = i;
}
 
int UFSet::findSet(int x)
{
    //找到元素所在的集合,也就是找到自己的最高的祖先,  
    //这也是判断两个元素是否在同一个集合中的主要依据。  
    if (parent[x] == x)//递归截止条件(最高祖先的祖先是其自身)
        return x;
 
    parent[x] = findSet(parent[x]);//递归,最终找到x的最高祖先,并且沿途找到所有的最高祖先  
    return parent[x];
}
 
void UFSet::unionSet(int x, int y)
{
    //将x和y所在的集合进行合并,利用findSet()判断x和y所在的集合是否相同,  
    //如果不同,则要把其中一个元素的祖先指向另一个元素的祖先。  
    int ux = findSet(x);//获取节点x的祖先  
    int uy = findSet(y);
    if (ux != uy)
        parent[ux] = uy;
}
int UFSet::getMinCost(int m)
{
    sort(edge, edge + m);//必须先对边排序,这样才能贪心的形成最小花费
    int sum = 0;
    for (int i = 0; i<m; i++)
    {
        int baseA = findSet(edge[i].acity);//找到城市a的祖先
        int baseB = findSet(edge[i].bcity);
        if (baseA != baseB)
        {
            parent[baseA] = baseB;//将城市a的祖先设置成b的祖先
            sum += edge[i].cost;
        }
    }
    return sum;
}
 
int main()
{
    int n = 0;
    while (cin >> n, n > 0)
    {
        int m = n*(n - 1) / 2;
 
        UFSet uset(10000);
        uset.makeSet(n);//初始化
        for (int i = 0; i < m; i++)
        {
            cin>> edge[i].acity>> edge[i].bcity>> edge[i].cost>> edge[i].isBuild;
            if (edge[i].isBuild == 1)//将已经建成的两个城市建立连接
                uset.unionSet(edge[i].acity, edge[i].bcity);
        }
        int mincost = uset.getMinCost(m);
        cout << mincost << endl;
    }
 
    return 0;
}
/**************************************************************
    Problem: 1028
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:30 ms
    Memory:1676 kb
****************************************************************/





题目1031:xxx定律

题目描述:
    对于一个数n,如果是偶数,就把n砍掉一半;如果是奇数,把n变成 3*n+ 1后砍掉一半,直到该数变为1为止。
    请计算需要经过几步才能将n变到1,具体可见样例。
输入:
    测试包含多个用例,每个用例包含一个整数n,当n为0 时表示输入结束。(1<=n<=10000)
输出:
    对于每组测试用例请输出一个数,表示需要经过的步数,每组输出占一行。
方法:
直接根据题意描述代码即可得出答案,比较简单
样例输入:
3
1
0
样例输出:
5
0

C++程序实现如下:

#include <iostream>
#include <string.h>
using namespace std;
int XxxLaw(int n);
int main()
{
 
    int x = 0;
    int count;
    while (cin >>x)
    {
        count = 0;
        if (x == 0)
        {
            break;
        }
        count = XxxLaw(x);
        cout <<count<< endl;
    }
    return 0;
}
 
int XxxLaw(int n)//直接根据题目意思描述程序即可
{
    int count = 0;
    while (n != 1)
    {
        if (n % 2 == 0)//如果是偶数
        {
            n = n / 2;
            count++;
        }
        else           //是奇数
        {
            n = 3 * n + 1;
            n = n / 2;
            count++;
        }
 
    }
     
    return count;
}
/**************************************************************
    Problem: 1031
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/

题目1032:ZOJ


题目描述:
读入一个字符串,字符串中包含ZOJ三个字符,个数不一定相等,按ZOJ的顺序输出,当某个字符用完时,剩下的仍然按照ZOJ的顺序输出。
输入:
题目包含多组用例,每组用例占一行,包含ZOJ三个字符,当输入“E”时表示输入结束。
1<=length<=100。
输出:
对于每组输入,请输出一行,表示按照要求处理后的字符串。
具体可见样例。
样例输入:
ZZOOOJJJ
ZZZZOOOOOJJJ
ZOOOJJ
E
样例输出:
ZOJZOJOJ
ZOJZOJZOJZOO
ZOJOJO


C++程序实现如下:

#include <iostream>
#include "string"
using namespace std;
bool printZOJ(string src);
int main()
{
	string str;
	while (cin >> str)
	{
		if (str.length() > 1000 || str.length() < 1)
			break;
		if (str.length() == 1 && str == "E")
			break;
		printZOJ(str);
		cout << endl;
		str.erase();
	}
	return 0;
}
bool printZOJ(string str)
{
	/*不要用如下方式统计Z,O,J的个数,除非输入每个字符是连续的挨在一起,否则情如下将处理不了:ZZZZOOOOZZZZZOOOOOOZZJJJJJJJ,
	int countZ = 0, countO = 0, countJ = 0;
	if (str.find("Z") != -1)//如果没发现Z,就不用计算个数了
	countZ = str.find_last_of("Z") - str.find("Z") + 1;//计算有多少个字符Z,因为这里加了一个1,所以当没有Z时无法正确判断出个数
	if (str.find("O") != -1)
	countO = str.find_last_of("O") - str.find("O") + 1;//计算有多少个字符Z
	if (str.find("J") != -1)
	countJ = str.find_last_of("J") - str.find("J") + 1;//计算有多少个字符Z
	*/
	int countZ = 0, countO = 0, countJ = 0;
	for (unsigned int i = 0; i<str.length(); i++)
	{
		if (str[i] == 'Z')
			countZ++;
		if (str[i] == 'O')
			countO++;
		if (str[i] == 'J')
			countJ++;
	}
	while (countZ>0 || countO>0 || countJ>0)
	{
		if (countZ > 0)//构造一个输出的先后顺序,准备循环输出“ZOJ”,如果被输出完了,对应字符就不用输出了
		{
			cout << 'Z';
			countZ--;
		}
		if (countO > 0)
		{
			cout << 'O';
			countO--;
		}
		if (countJ > 0)
		{
			cout << 'J';
			countJ--;
		}
	}
	return true;
}


题目1033:继续xxx定律

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:5018

解决:1208

题目描述:
    当n为3时,我们在验证xxx定律的过程中会得到一个序列,3,5,8,4,2,1,将3称为关键数,5,8,4,2称为覆盖数。现在输入n个数字a[i],根据关键数与覆盖数的理论,我们只需要验证其中部分数就可以确定所有数满足xxx定律,输出输入的n个数中的关键数。如果其中有多个关键数的话按照其输入顺序的逆序输出。
输入:
    输入数据包含多个用例,每个用例首先包含一个整数n,然后接下来一行有n个整数a[i],其中: 1<=n<=500, 1<a[i]<=1000
输出:
    请计算并输出数组a中包含的关键数,并按照其输入顺序的逆序输出,每个用例输出占一行。
样例输入:
3
3 8 4
5
3 8 4 7 15
5
3 8 4 15 7
0
样例输出:
3
15 7 3
7 15 3
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include "math.h"  
 
using namespace std;
 
//判断当前这个数key是否在数组vec的某个位置并返回它的位置
int isOneOfArray(int key, vector<bool> &vecflag, vector<int> &vec)
{
    for (size_t i = 0; i < vec.size(); i++)
    {
        if (vecflag[i] != true && key == vec[i])
            return i;
    }
    return -1;
}
 
int main(void)
{
    int n = 0;
     
    while (cin>>n)
    {
        vector<bool> vecflag(n,0);//用vecflag来记录已经被确定为覆盖数的数
        vector<int> vec(n, 0);
        //接收输入
        for (int i = 0; i < n; i++)
            cin >> vec[i];
         
        for (int i = 0; i < n; i++)
        {
            int val = vec[i];//判断当前这个数组的数产生的覆盖数
            while (val != 1)
            {
                if (val % 2 == 0)//如果是偶数,直接减半
                {
                    val = val / 2;
                    if (isOneOfArray(val, vecflag,vec) != -1)
                        vecflag[isOneOfArray(val, vecflag, vec)] = true;//确定他为覆盖数
                }
                else//是奇数,先...再减半
                {
                    val = 3 * val + 1;
                    val = val / 2;
                    if (isOneOfArray(val, vecflag, vec) != -1)
                        vecflag[isOneOfArray(val, vecflag, vec)] = true;
                }
            }
        }
 
        for (size_t i = 0; i < n; i++)
        {//还为false的位置就是关键数
            if (vecflag[n - i - 1] != true)
                cout << vec[n - i - 1] << " ";//逆序输出
        }
        cout << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1033
    User: EbowTang
    Language: C++
    Result: Wrong Answer
****************************************************************/




题目1039:Zero-complexity Transposition

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:3117

解决:1269

题目描述:

You are given a sequence of integer numbers. Zero-complexity transposition of the sequence is the reverse of this sequence. Your task is to write a program that prints zero-complexity transposition of the given sequence.

输入:

For each case, the first line of the input file contains one integer n-length of the sequence (0 < n ≤ 10 000). The second line contains n integers numbers-a1, a2, …, an (-1 000 000 000 000 000 ≤ ai ≤ 1 000 000 000 000 000).

输出:

For each case, on the first line of the output file print the sequence in the reverse order.

样例输入:
5
-3 4 6 -8 9
样例输出:
9 -8 6 4 -3
#include "vector"  
#include <iostream>  
#include "fstream"
#include "algorithm"  
#include <stdio.h>
#include "string"
#include <cmath>
#include <cstdlib>
#include "map"

using namespace std;

int main()
{
	int n = 0;
	while (cin >> n, n > 0)
	{//32位的int型最大值为42亿左右,容不下题目所要求的数
		vector<long long> nums1(n,0);
		for (int i = 0; i < n; i++)
			cin >> nums1[i];
		
		for (int i = n - 1; i >= 1; i--)
			cout << nums1[i] << " ";
		cout << nums1[0] << endl;
	}
	return 0;
}


题目1040:Prime Number

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:5349

解决:2212

题目描述:

Output the k-th prime number.

输入:

k≤10000

输出:

The k-th prime number.

样例输入:
3
7
样例输出:
5
17
#include "vector"  
#include <iostream>  
#include "fstream"
#include "algorithm"  
#include <stdio.h>
#include "string"
#include <cmath>
#include <cstdlib>
#include "map"
 
using namespace std;
 
vector<int> basenum;//用于存储素数
//素数判断法:任何一个合数都可以表现为适当个素数的乘积的形式,
//所以我们只用小于sqrt(number)的素数去除要判断的数number即可,
//比如要判断100以内的素数,只用10以内的2,3,5,7就够了,10000以内的数用100以内的素数判断足以。
 
void initPrime()
{
    basenum.reserve(10001);//预留空间
    basenum.push_back(2);
    basenum.push_back(3);
    basenum.push_back(5);
    basenum.push_back(7);//先压入4个素数
    int  number=11;
     
    for (int i = 5; i <= 10000; number++)//计算出10000个素数
    {
        int flag = true;
        int tmp = static_cast<int>(sqrt(number));
        //判断是否是素数
        int j = 0;
        while (basenum[j] <= tmp)
        {
            if (number % basenum[j] == 0)
            { //此时合数
                flag = false; 
                break; 
            }
            j++;
        }
        if (flag)
        { 
            basenum.push_back(number);
            i++;
        }
    }
}
 
int main()
{
    int n;
    initPrime();
    while (cin>>n)
        printf("%d\n", basenum[n - 1]);
    return 0;
}
/**************************************************************
    Problem: 1040
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1536 kb
****************************************************************/





题目1041:Simple Sorting

题目描述:

You are given an unsorted array of integer numbers. Your task is to sort this array and kill possible duplicated elements occurring in it.

输入:

For each case, the first line of the input contains an integer number N representing the quantity of numbers in this array(1≤N≤1000). Next N lines contain N integer numbers(one number per each line) of the original array.

输出:

For each case ,outtput file should contain at most N numbers sorted in ascending order. Every number in the output file should occur only once.

样例输入:
6
8 8 7 3 7 7
样例输出:
3 7 8

c++实现如下:

#include <iostream>  
#include "vector"
#include <algorithm>
using namespace std;
 
int main()
{
    int N = 0;
    while (cin>>N)
    {
        if (N > 1000 || N < 0)
            break;
        vector<int>  v(N,0);
        for (int i = 0; i < N;i++)
            cin >> v[i];
     
        sort(v.begin(),v.end());
 
        for (int i = 0; i < v.size(); i++)
        {
            if (i == 0)
                cout << v[i];
            else
                cout <<" "<<v[i];
             
            while (v[i] == v[i+1])
            {
                i++;
                if (i == (v.size() - 1))
                    break;
            }
        }
    cout << endl;
    }
}
/**************************************************************
    Problem: 1041
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/




题目1045:百鸡问题

题目描述:

    用小于等于n元去买100只鸡,大鸡5元/只,小鸡3元/只,还有1/3元每只的一种小鸡,分别记为x只,y只,z只。编程求解x,y,z所有可能解。

输入:

    测试数据有多组,输入n。

输出:

    对于每组输入,请输出x,y,z所有可行解,按照x,y,z依次增大的顺序输出。


方法:

穷举所有可能

样例输入:
40
样例输出:
x=0,y=0,z=100
x=0,y=1,z=99
x=0,y=2,z=98
x=1,y=0,z=99

C++程序实现如下:
#include <iostream>  
using namespace std;
int main()
{
    int n = 40;
    while (cin>>n)
    {//穷举所有可能
        for (int x = 0; x <= n / 5; x++)//x为买5元鸡的最大可能数量,以下同理
        {
            for (int y = 0; y <= n / 3; y++)
            {
                for (int z = 0; z <= 3 * n; z++)
                {
                    if ((x + y + z) == 100 && 5 * x + 3 * y + z*(1.0 / 3) <= n)
                        cout << "x=" << x << ",y=" << y << ",z=" << z << endl;
                }
            }
        }
    }
 
    return 0;
}
/**************************************************************
    Problem: 1045
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:30 ms
    Memory:1520 kb
****************************************************************/



题目1046:求最大值

题目描述:

输入10个数,要求输出其中的最大值。

输入:

测试数据有多组,每组10个数。

输出:

对于每组输入,请输出其最大值(有回车)。


方法:

暴力搜索,一个个对比数据获取最大值

样例输入:
10 22 23 152 65 79 85 96 32 1
样例输出:
max=152


C++程序实现如下:


#include <iostream>
using namespace std;
int getMax(int *num);
int main()
{
    int num[10] = {0};
    int a = 0;
    int count = 0;
    while (cin>>a)
    {
        num[count] = a;
        count++;
        if (count==10)
        {
            int max = 0;
            max = getMax(num);
            cout <<"max="<< max << endl;
            count = 0;
            continue;
        }
    }
    return 0;
}
 
int getMax(int *num)
{
    int max = 0;
    for (int i = 0; i < 10;i++)
    {
        if (max<num[i])
        {
            max = num[i];
        }
    }
    return max;
}
/**************************************************************
    Problem: 1046
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/


题目1047:素数判定

题目描述:

给定一个数n,要求判断其是否为素数(0,1,负数都是非素数)。

输入:

测试数据有多组,每组输入一个数n。

输出:

对于每组输入,若是素数则输出yes,否则输入no。

样例输入:
13
样例输出:
yes

#include <iostream>
using namespace std;
bool IsPrimeNum(int num);
int main()
{
 
    int a = 0;
    bool flag = false;
 
    while (cin >> a)
    {
        flag = IsPrimeNum(a);
        if (flag == true)
        {
            cout << "yes" << endl;
            continue;
        }
        else
        {
            cout << "no" << endl;
            continue;
        }
    }
    return 0;
}
 
bool IsPrimeNum(int num)
{
    if (num <= 1)
        return false;
    for (int i = 2; i <= num/2; i++)
    {
        if (num % i == 0)//一旦可以整除立马返回他不是素数  
            return false;
    }
    return true;
}
/**************************************************************
    Problem: 1047
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/


题目1048:判断三角形类型

题目描述:

给定三角形的三条边,a,b,c。判断该三角形类型。

输入:

测试数据有多组,每组输入三角形的三条边。

输出:

对于每组输入,输出直角三角形、锐角三角形、或是钝角三角形。

样例输入:
3 4 5
样例输出:
直角三角形

#include <iostream>
using namespace std;
int WhatTriangle(int *num);
int main()
{
 
    int a[3] = {0};
    int count = 0;
    int b = 0;
    while (cin >>b)
    {
        a[count] = b;
        count++;
        if (count==3)
        {
            int flag = WhatTriangle(a);
 
            switch (flag)
            {
            case 0:
                cout << "直角三角形" << endl;
                count = 0;
                break;
            case 1:
                cout << "锐角三角形" << endl;
                count = 0;
                break;
            case 2:
                cout << "钝角三角形" << endl;
                count = 0;
                break;
            default:
                break;
            }
 
            /*
            if (flag == 0)
            {
                cout << "直角三角形" << endl;
                count = 0;
                continue;
            }
            else if (flag == 1)
            {
                cout << "锐角三角形" << endl;
                count = 0;
                continue;
            }
            else
            {
                cout << "钝角三角形" << endl;
                count = 0;
                continue;
            }*/
        }
         
    }
    return 0;
}
 
int WhatTriangle(int *num)
{
    int a = num[0];
    int b = num[1];
    int c = num[2];
 
    int x = a*a + b*b - c*c;
    int y = a*a + c*c - b*b;
    int z = b*b + c*c - a*a;
    if (x == 0 || y == 0 || z == 0)//显然是直角三角形
    {
        return 0;
    }
    else if (x > 0 && y > 0 && z > 0)
    {
        return 1;
    }
    else
    {
        return 2;
    }
}
/**************************************************************
    Problem: 1048
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/


题目1049:字符串去特定字符

题目描述:

输入字符串s和字符c,要求去掉s中所有的c字符,并输出结果。

输入:

测试数据有多组,每组输入字符串s和字符c。

输出:

对于每组输入,输出去除c字符后的结果。

样例输入:
heallo
a
样例输出:
hello
#include <iostream>
#include <string.h>
using namespace std;
#define  max 1000
void deleteChar(char *src,char b,int len);
int main()
{
 
    char a[max]="";
    memset(a, 0, sizeof(a));
    while (cin >>a)
    {
        char dela;
        cin >> dela;
        int len = strlen(a);
        deleteChar(a, dela, len);//在字符数组a中如果某一字符不为dela则打印出来,否则不打印,接着继续
        memset(a, 0, sizeof(a));
    }
    return 0;
}
 
void deleteChar(char *src,char b,int len)
{
    for (int j = 0; j < len;j++)
    {
        if (src[j] != b)
        {
            cout << src[j];
        }
    }
    cout << endl;
}
/**************************************************************
    Problem: 1049
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/





你可能感兴趣的:(数据结构,算法,ACM,九度)