<C/C++算法>九度OJ题目1201--1358解题练习(六)


题目1201:二叉排序树

题目描述:

    输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历。

输入:

    输入第一行包括一个整数n(1<=n<=100)。
    接下来的一行包括n个整数。

输出:

    可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序、中序和后序遍历。
    每种遍历结果输出一行。每行最后一个数据之后有一个空格。

样例输入:
5
1 6 5 9 8
样例输出:
1 6 5 9 8 
1 5 6 8 9 
5 8 9 6 1 
提示:

输入中可能有重复元素,但是输出的二叉树遍历序列中重复元素不用输出。

#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
// 节点定义  
class BSTNode
{
public:
    BSTNode(int newData )// 默认构造  
    {
        pRight = NULL;
        pLeft = NULL;
        value = newData;
    }
    ~BSTNode();
    friend class LinkBST;// 允许链表类随意访问节点数据  
 
private:
    int value;
    BSTNode *pRight;
    BSTNode *pLeft;
};
 
// 有头结点的二叉搜索树定义   
class LinkBST
{
public:
    LinkBST(){
        m_pRoot = NULL;
    };
    ~LinkBST(){};
    BSTNode* getRoot() const
    {
        return m_pRoot;
    }
    // 插入节点
    void InsertBTNode(int newData);
    // 中序遍历  
    void inOrder(BSTNode *pRoot);
    // 先序遍历    
    void preOrder(BSTNode *pRoot);
    // 后序遍历    
    void postOrder(BSTNode *pRoot);
private:
    BSTNode *m_pRoot;
};
 
// 中序遍历  
void LinkBST::inOrder(BSTNode *pNode)
{
    if (pNode != NULL)
    {
        inOrder(pNode->pLeft);
        cout << pNode->value << " ";
        inOrder(pNode->pRight);
    }
}
 
// 先序遍历
void LinkBST::preOrder(BSTNode *pNode)
{
    if (pNode != NULL)
    {
        cout << pNode->value << " ";
        preOrder(pNode->pLeft);
        preOrder(pNode->pRight);
    }
}
 
// 后序遍历
void LinkBST::postOrder(BSTNode *pNode)
{
    if (pNode != NULL)
    {
        postOrder(pNode->pLeft);
        postOrder(pNode->pRight);
        cout << pNode->value << " ";
    }
}
 
// 插入节点
void LinkBST::InsertBTNode(int newData)
{
    BSTNode *newNode = new BSTNode(newData);
 
    if (m_pRoot == NULL)
    {
        m_pRoot = newNode;
        return;
    }
 
    BSTNode *pPre = NULL;//用于保存上一个节点    
    BSTNode *pCur = m_pRoot;
    //寻找要插入的节点的位置 (一定是某个叶子)  
    while (pCur != NULL)
    {
        pPre = pCur;//保存节点  
        if (newNode->value < pCur->value)
            pCur = pCur->pLeft;//较小值则移到节点的左子树    
        else if (newNode->value > pCur->value)
            pCur = pCur->pRight;
        else
            break;
    }
 
    //建立连接  (不对)
    if (newNode->value < pPre->value)
        pPre->pLeft = newNode;
    else if (newNode->value > pPre->value)
        pPre->pRight = newNode;
}
 
 
int main()
{
    int n = 0;
    while (cin >> n)
    {
        LinkBST bst;
        int val = 0;
        for (int i = 0; i < n; i++)
        {
            cin >> val;
            bst.InsertBTNode(val);
        }
        bst.preOrder(bst.getRoot());
        cout << endl;
        bst.inOrder(bst.getRoot());
        cout << endl;
        bst.postOrder(bst.getRoot());
        cout << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1201
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:100 ms
    Memory:2972 kb
****************************************************************/




题目1202:排序

题目描述:

    对输入的n个数进行排序并输出。

输入:

    输入的第一行包括一个整数n(1<=n<=100)。
    接下来的一行包括n个整数。

输出:

    可能有多组测试数据,对于每组数据,将排序后的n个整数输出,每个数后面都有一个空格。
    每组测试数据的结果占一行。

样例输入:
4
1 4 3 2
样例输出:
1 2 3 4 
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
 
using namespace std;
 
int main()
{
    int n = 0;
    while (cin>>n)
    {
        vector<int> vec(n);
        for (int i = 0; i < n; i++)
            cin >> vec[i];
        sort(vec.begin(),vec.end());
        for (int i = 0; i < n; i++)
            cout<< vec[i]<<" ";
        cout << endl;
    }
    return 0;
}
 
/**************************************************************
    Problem: 1202
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:50 ms
    Memory:1520 kb
****************************************************************/



题目1203:IP地址

题目描述:

    输入一个ip地址串,判断是否合法。

输入:

    输入的第一行包括一个整数n(1<=n<=500),代表下面会出现的IP地址的个数。
    接下来的n行每行有一个IP地址,IP地址的形式为a.b.c.d,其中a、b、c、d都是整数。

输出:

    可能有多组测试数据,对于每组数据,如果IP地址合法则输出"Yes!”,否则输出"No!”。

样例输入:
2
255.255.255.255
512.12.2.3
样例输出:
Yes!
No!
提示:

合法的IP地址为:
a、b、c、d都是0-255的整数。

#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
int main()
{
    int n;
    while (cin >> n)
    {
        for (int i = 0; i < n; i++)
        {
            int a[4];
            bool flag = true;
            char c1, c2, c3;
            cin >> a[0]>>c1 >> a[1] >>c2>> a[2] >>c3>> a[3];
 
            for (int j = 0; j < 4; j++)
            {
                if (a[j] > 255 || a[j] < 0)
                    flag = false;
            }
            if (flag)
                cout << "Yes!"<< endl;
            else
                cout << "No!" << endl;
        }
    }
    return 0;
}
/**************************************************************
    Problem: 1203
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/

题目1204:农夫、羊、菜和狼的故事

题目描述:

有一个农夫带一只羊、一筐菜和一只狼过河.
果没有农夫看管,则狼要吃羊,羊要吃菜.
但是船很小,只够农夫带一样东西过河。
问农夫该如何解此难题?

输入:

题目没有任何输入。

输出:

题目可能有种解决方法,求出步骤最少的解决方法,
按顺序输出农夫想把羊、菜、狼全部运过河需要哪几个步骤。
如果需要将羊带过河去则输出“sheep_go”。
如果需要将羊带回来则输出“sheep_come”。
如果需要将菜带过河去则输出“vegetable_go”。
如果需要将菜带回来则输出“vegetable_come”。
如果需要将狼带过河去则输出“wolf_go”。
如果需要将狼带回来则输出“wolf_come”。
如果需要空手返回则输出“nothing_come”。
如果需要空手过河则输出“nothing_go”。
每输出一种方案,输出一行“succeed”。

样例输入:
 
 
样例输出:
 
 
提示:

题目可能有多组解决方法,每种方法输出后要再空一行。
一种方法中的多句话,每句话占一行。

#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
//第一次带羊过去, 空船回来.
//第二次带狼过去, 带羊回来.
//第三次带草过去, 空船回来.
//第四次带羊过去.
int main()
{
    cout << "sheep_go" << endl;
    cout << "nothing_come" << endl;//第一次带羊过去, 空船回来.
 
    cout << "wolf_go" << endl;
    cout << "sheep_come" << endl;//第二次带狼过去, 带羊回来。狼已经过去,
 
    cout << "vegetable_go" << endl;
    cout << "nothing_come" << endl;//第三次带草过去, 空船回来。草已经过去
 
    cout << "sheep_go" << endl;//第四次带羊过去。羊已经过去
    return 0;
}
/**************************************************************
    Problem: 1204
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1516 kb
****************************************************************/




题目1205:N阶楼梯上楼问题

题目描述:

N阶楼梯上楼问题:一次可以走两阶或一阶,问有多少种上楼方式。(要求采用非递归)

输入:

输入包括一个整数N,(1<=N<90)。

输出:

可能有多组测试数据,对于每组数据,
输出当楼梯阶数是N时的上楼方式个数。

样例输入:
4
样例输出:
5
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
//当n=1时,ans=1,当n=2时,ans=2  
//当n=3时,ans=3,当n=4时,ans=5  
//当n=5时,ans=8  
//令跳到第i个台阶时的方法数为f(i)  
//当我们跳2到达的第i个台阶,方法数显然就是f(i-2)
//当我们跳1到达的第i个台阶,方法数显然就是f(i-1)  
//更显然的是两种选择都可以,所以f(i)=f(i-1)+f(i-2)  
int main()
{
    int  n;
    while (cin >> n)
    {
        vector<long long> vec(n + 1);
        vec[1] = 1;
        vec[2] = 2;
        for (int i = 3; i <= n; i++)
        {
            vec[i] = vec[i - 1] + vec[i - 2];
        }
        cout << vec[n] << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1205
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/



题目1206:字符串连接

题目描述:

不借用任何字符串库函数实现无冗余地接受两个字符串,然后把它们无冗余的连接起来。

输入:

每一行包括两个字符串,长度不超过100。

输出:

可能有多组测试数据,对于每组数据,
不借用任何字符串库函数实现无冗余地接受两个字符串,然后把它们无冗余的连接起来。
输出连接后的字符串。

样例输入:
abc def
样例输出:
abcdef
#include "string.h"
#include <iostream>
  
using namespace std;
  
int MyStrcat(char dstStr[], char srcStr[])
{
    char *pdst = dstStr;
    char *psrc = srcStr;
    int len1 = strlen(dstStr);
    int len2 = strlen(srcStr);
    int i, j;
    for ( i = len1, j = 0; j < len2; j++, i++)
        dstStr[i] = srcStr[j];
    dstStr[i] = '\0';
    return 0;
}
int main()
{
    char src1[200] = {'\0'}, src2[100] = { '\0' };
    while (cin>>src1>>src2)
    {
        MyStrcat(src1,src2);
        cout << src1 << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1206
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:20 ms
    Memory:1520 kb
****************************************************************/


题目1209:最小邮票数

题目描述:

    有若干张邮票,要求从中选取最少的邮票张数凑成一个给定的总值。
    如,有1分,3分,3分,3分,4分五张邮票,要求凑成10分,则使用3张邮票:3分、3分、4分即可。

输入:

    有多组数据,对于每组数据,首先是要求凑成的邮票总值M,M<100。然后是一个数N,N〈20,表示有N张邮票。接下来是N个正整数,分别表示这N张邮票的面值,且以升序排列。

输出:

      对于每组数据,能够凑成总值M的最少邮票张数。若无解,输出0。

样例输入:
10
5
1 3 3 3 4
样例输出:
3
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
int v, N;
int w[1000];
int dp[1000];
#define inf 1000
//令dp[i]表示邮票总价值为i的凑齐时的最小邮票数
//每一个物品,我们可以选择,也可以不选
//自底向上遍历求解,当总价值为j,在选择第i个物品时
//如果选,显然,dp[j] =  dp[j - w[i]] + 1
//如果不选,那就没变化,dp[j] = dp[j]
void MinNumStamp()
{
    for (int j = 0; j < 1000; j++)
        dp[j] = inf;
     
    dp[0] = 0;//总价值为0,不需要邮票数
 
    for (int i = 1; i <= N; ++i)//遍历物品,1到N
    {
        for (int j = v; j >= w[i]; --j)//遍历邮票总价值,总价值到w[i]
        {
            dp[j] = min(dp[j], dp[j - w[i]] + 1);
        }
    }
 
    if (dp[v] >= 1000)
        cout << 0 << endl;
    else
        cout << dp[v] << endl;
}
int main()
{
    while (cin >> v >> N)
    {
        for (int i = 1; i <= N; ++i)
            cin>>w[i];
        MinNumStamp();
    }
    return 0;
}
/**************************************************************
    Problem: 1209
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:190 ms
    Memory:1528 kb
****************************************************************/



题目1214:丑数

题目描述:

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。
习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

输入:

输入包括一个整数N(1<=N<=1500)。

输出:

可能有多组测试数据,对于每组数据,
输出第N个丑数。

样例输入:
3
样例输出:
3

技巧法:

#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
 
using namespace std;
 
void countUglyNums(vector<int> &vec)
{
    int t2 = 1, t3 = 1, t5 = 1;
    int cnt = 1;
    while (cnt <= 1501)
    {   //用2,3,5这三个数相乘来组成丑数
        //唯一需要确保的就是我们组成的丑数是按从小到大的关系出现的
        //用三个数来维护渐乘的结果,总是选出最小的丑数
        int a = vec[t2] * 2, b = vec[t3] * 3, c = vec[t5] * 5;
        int minUgly = min(min(a, b), c);//求三数中最小的一个
        vec.push_back(minUgly);//第cnt个丑数总是在数组末尾
        //更新丑数,新丑数必须必原丑数大
        while (a <= minUgly)
        { 
            ++t2; 
            a = vec[t2] * 2; 
        }
        while (b <= minUgly)
        { 
            ++t3;
            b = vec[t3] * 3;
        }
        while (c <= minUgly)
        { 
            ++t5; 
            c = vec[t5] * 5; 
        }
        cnt++;
    }
}
 
int main()
{
    int n;
    vector<int> vec;
    vec.push_back(0);
    vec.push_back(1);
    countUglyNums(vec);
    while (cin>>n)
    {
        cout << vec[n] << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1214
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:20 ms
    Memory:1520 kb
****************************************************************/

暴力破解法

#include <iostream>
 
using namespace std;
 
bool isUglyNum(int key)
{
    while (true)
    {
        if (key % 2 == 0)
        {
            key = key / 2;
            if (key == 1)
                return true;
        }
        else if (key % 3 == 0)
        {
            key = key / 3;
            if (key == 1)
                return true;
        }
        else if (key % 5 == 0)
        {
            key = key / 5;
            if (key == 1)
                return true;
        }
        else
            return false;
    }
    return true;
}
int main()
{
    int n = 0;
    while (cin>>n)
    {
        int count = 1,i=2;
        while (true)
        {
            if (isUglyNum(i))
                count++;
            if (count == n)
            {
                cout << i << endl;
                break;
            }
            i++;
        }
    }
    return 0;
}
/**************************************************************
    Problem: 1214
    User: EbowTang
    Language: C++
    Result: Time Limit Exceed
****************************************************************/



题目1252:回文子串

题目描述:

输入一个字符串,输出该字符串中对称的子字符串的最大长度。
比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。

输入:

存在多组数据,每组数据一行字符串,长度不大于100。

输出:

输出回文子串的最大长度。

样例输入:
google
样例输出:
4
#include "string"
#include "algorithm"
#include <iostream>
 
using namespace std;
 
bool IsBackChar(const string src)
{
    for (size_t i = 0; i < src.size(); i++)
    if (src[i] != src[src.size() - i - 1])
        return false;
 
    return true;
}
 
int main()
{
    string str;
    while (cin >> str)
    {//level就是回文
        int max = 1;
        for (size_t i = 1; i <= str.size(); i++)
        {
            bool flag = false;
            for (size_t k = 0; k < i; k++)
            {//穷举所有子串情况进行判断
                string substr(str, k, i - k);//截取str字符串中从第k个位置起后的i-k个子串
                if (IsBackChar(substr) && substr.size() > max)
                    max = substr.size();
            }
        }
        cout << max << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1252
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:10 ms
    Memory:1520 kb
****************************************************************/




题目1256:找出两个只出现了一次的数字

题目描述:

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

输入:

输入的第一行包括一个整数N(1<=N<=1000)。
接下来的一行包括N个整数。

输出:

可能有多组测试数据,对于每组数据,
找出这个数组中的两个只出现了一次的数字。
输出的数字的顺序为从小到大。

样例输入:
6
2 3 9 3 7 2 
样例输出:
7 9
#include <cstdio>  
#include <cstdlib>  
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>  
 
using namespace std;
 
int main()
{
    int  n;
    while (cin >> n && n >= 1 && n <= 1000)
    {
        vector<int> vec(n, 0);
        for (int i = 0; i < n; i++)
            scanf("%d", &vec[i]);
        //直接排序
        sort(vec.begin(), vec.end());
        //准备获取这两个数
        vector<int> ans(2, 0);
        int k = 0;
        //直接判断首尾是否是只出现一次的数
        if (n>2 && vec[0] != vec[1])
            ans[k++] = vec[0];
        if (n>2 && vec[n - 1] != vec[n - 2])
            ans[k++] = vec[n - 1];
        //判断除去首尾后的中间数是否是只出现一次
        for (int i = 1; i < n -1; i++)
        {
            if (k == 2)
                break;
            if (vec[i] != vec[i - 1] && vec[i] != vec[i + 1])//只出现一次的充分条件
                ans[k++] = vec[i];
        }
        //按照大小输出
        if (ans[0]>ans[1])
            cout << ans[1] << " " << ans[0] << endl;
        else
            cout << ans[0] << " " << ans[1] << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1256
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:860 ms
    Memory:1520 kb
****************************************************************/

题目1283:第一个只出现一次的字符

题目描述:

在一个字符串(1<=字符串长度<=10000,全部由大写字母组成)中找到第一个只出现一次的字符。

输入:

输入有多组数据
每一组输入一个字符串。

输出:

输出第一个只出现一次的字符下标,没有只出现一次的字符则输出-1。

样例输入:
ABACCDEFF
AA
样例输出:
1
-1

#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
//find_first_of 查找字符c在字符串中第一次出现的位置(默认从0位置开始找),
//并返回他的第一个出现的位置,如果没有则返回string::npos;
//即最后一个字符的后面一个位置
// 函数find_last_of()查找最后一个出现的c。匹配的位置是返回值。
//如果没有匹配发生,则函数返回 - 1.
 
int main()
{
    string s;
     
    while (cin >> s)
    {
        int i;
        bool flag = false;
        for (i = 0; i < s.size(); ++i)
        {
             
            if (s.find_first_of(s[i]) == s.find_last_of(s[i]))
            {
                flag = true;
                break;
            }
        }
        if (flag)
            cout << i << endl;
        else
            cout << "-1" << endl;
    }
    return 0;
}
 
/**************************************************************
    Problem: 1283
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:170 ms
    Memory:1520 kb
****************************************************************/




题目1325:Battle Over Cities

题目描述:

It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.

For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city1 is occupied by the enemy, we must have 1 highway repaired, that is the highway city2-city3.

输入:

Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.

输出:

For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.

样例输入:
3 2 3
1 2
1 3
1 2 3
样例输出:
1
0
0
#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]);
    return parent[x];
}
 
void UFSet::unionSet(int x, int y)
{
    int ux = findSet(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 N = 0, M = 0, K = 0;
    while (cin >> N >> M >> K)
    {
        UFSet uset(10000);
        //接收m对已经联通的城市
        vector<int> xvec(M,0), yvec(M,0);
 
        for (int i = 0; i<M; i++)
            cin >> xvec[i] >> yvec[i];
         
        vector<int> vec(K,0);
 
        for (int i = 0; i < K; i++)
            cin >> vec[i];
         
        for (int i = 0; i < K; i++)
        {
            uset.makeSet(N);//初始化  
            for (int j = 0; j < M; j++)
            {
                if (vec[i] != xvec[j] && vec[i] != yvec[j])//如果这个城市被占领,就不要建立连接了。模拟切断
                    uset.unionSet(xvec[j], yvec[j]);
            }
            int highways = uset.getSets(N) - 2;//为什么是2?去除被占城市,并且两个独立的集合修一条路
            cout << highways  << endl;
        }
    }
    return 0;
}
/**************************************************************
    Problem: 1325
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:490 ms
    Memory:5416 kb
****************************************************************/


题目1347:孤岛连通工程

题目描述:

现在有孤岛n个,孤岛从1开始标序一直到n,有道路m条(道路是双向的,如果有多条道路连通岛屿i,j则选择最短的那条),请你求出能够让所有孤岛都连通的最小道路总长度。

输入:

数据有多组输入。
每组第一行输入n(1<=n<=1000),m(0<=m<=10000)。
接着m行,每行输入一条道路i j d(0<=d<=1000),(i,j表示岛屿序号,d表示道路长度)。

输出:

对每组输入输出一行,如果能连通,输出能连通所有岛屿的最小道路长度,否则请输出字符串"no"。

样例输入:
3 5
1 2 2
1 2 1
2 3 5
1 3 3
3 1 2
4 2
1 2 3
3 4 1
样例输出:
3
no
</pre><pre>

#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 = 1000000;
	}
	int acity;//岛屿a    
	int bcity;//岛屿b    
	int dst;  //岛屿a到b的距离    

};

Edge edge[10000];

bool cmp(Edge mode1, Edge mode2)
{
	return mode1.dst < mode2.dst;
}


class UFSet
{
public:
	UFSet(int nsize)
	{
		size = nsize;
		parent = new int[size + 1];
	}
	~UFSet()
	{
		delete[] parent;
		parent = NULL;
	}

	// 初始化每个元素的祖先   为自身
	void makeSet(int n);

	// 找到元素x的祖先元素   
	int findSet(int x);

	// 获取最小生成数路劲
	void getMinWay(int m, 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]);
	return parent[x];
}

void UFSet::getMinWay(int m, int n)
{
	sort(edge + 1, edge + m + 1, cmp);//必须先对边排序(根据边的修建费用),这样才能贪心的形成最小花费    
	int sum = 0;
	int ct = 0;
	for (int i = 1; i <= m; i++)
	{
		int baseA = findSet(edge[i].acity);//找到城市a的祖先  
		int baseB = findSet(edge[i].bcity);
		if (baseA != baseB)
		{
			ct++;
			parent[baseA] = baseB;
			sum += edge[i].dst;
		}
	}
	if (ct == n - 1)
		printf("%d\n", sum);
	else
		printf("no\n");

}

int main()
{
	int n = 0;//岛屿数目
	int m = 0;//道路数目
	while (cin >> n >> m)
	{
		UFSet uset(n);
		uset.makeSet(n);//初始化每个城市的祖先为自身    
		int a = 0, b = 0, ndst = 0;

		for (int i = 1; i <= m; i++)
			scanf("%d%d%d", &edge[i].acity, &edge[i].bcity, &edge[i].dst);

		//麻痹,不是说好多条边联通两个岛屿时,选择最小的变么?麻痹!
		//接收边的时候不应该这样么:
		/*
		int a = 0, b = 0, ndst = 0;
		for (int i = 1; i <= m; i++)
		{
			cin >> a >> b >> ndst;
			edge[i].acity = a;
			edge[i].bcity = b;
			if (edge[i].dst > ndst)
			edge[i].dst = ndst;
		}
		*/
		uset.getMinWay(m, n);
	}

	return 0;
}
/**************************************************************
Problem: 1347
User: EbowTang
Language: C++
Result: Accepted
Time:840 ms
Memory:1640 kb
****************************************************************/



题目1348:数组中的逆序对

题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
输入:
每个测试案例包括两行:
第一行包含一个整数n,表示数组中的元素个数。其中1 <= n <= 10^5。
第二行包含n个整数,每个数组均为int类型。
输出:
对应每个测试案例,输出一个整数,表示数组中的逆序对的总数。
样例输入:
4
7 5 6 4
样例输出:
5
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>  
 
using namespace std;
//本题为算法导论上的题目
unsigned long long cnt;//防止同名,不要去变量名为count
 
//模拟合并过程,在归并过程中总是在
void merge(vector<int> &v, int low, int mid, int high) 
{
    if (high <= low) 
        return;
    int len = high - low + 1;
    vector<int> tmpvec(len);//临时数组
    int idxleft = low;//左边数组的起始位置量
    int idxright = mid + 1;//右边的位置量
    int idxtmp = 0;//填充临时数组时的位置递增量
    while (idxleft <= mid && idxright <= high)
    {//总是将较小的先放入临时数组,形成有序数组
        if (v[idxleft] > v[idxright])
        {
            tmpvec[idxtmp++] = v[idxright++];
            cnt += mid - idxleft + 1;
            //说明归并时,左边的数组从位置idxleft到mid的元素都比右边的idxright位置的元素大
            //他们都是逆序对
        }
        else
        {//右边的数组元素大,不进行计数
            tmpvec[idxtmp++] = v[idxleft++];
        }
    }
 
    if (idxleft > mid)
    {//归并时,右边剩余
        while (idxtmp < tmpvec.size())//这个条件别忘了
            tmpvec[idxtmp++] = v[idxright++];
    }
    if (idxright > high)
    {//归并时,左边剩余
        while (idxtmp < tmpvec.size())
            tmpvec[idxtmp++] = v[idxleft++];
    }
 
    //用有序的临时数组纠正原数组的无序值
    int tmpcnt = 0;
    while (tmpcnt < tmpvec.size())
    {
        v[low + tmpcnt] = tmpvec[tmpcnt];
        tmpcnt++;
    }
}
 
//合并排序
void mergeSort(vector<int> &v, int low, int high) 
{
    if (high <= low)
        return;
 
    int mid = (low + high) / 2;
    mergeSort(v, low, mid);
    mergeSort(v, mid + 1, high);
    merge(v, low, mid, high);//最底层是两个元素进行合并
}
 
int main() 
{
    int n=0;
    while (cin >> n) 
    {
        vector<int> vec(n);
        cnt = 0;//全局变量
        for (int i = 0; i < n; ++i) 
            cin >> vec[i];
         
        mergeSort(vec, 0, n - 1);
        cout << cnt << endl;
    }
    return 0;
}
 
 
/**************************************************************
    Problem: 1348
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:190 ms
    Memory:2500 kb
****************************************************************/




题目1350:二叉树的深度

题目描述:

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

输入:

第一行输入有n,n表示结点数,结点号从1到n。根结点为1。 n <= 10。

接下来有n行,每行有两个个整型a和b,表示第i个节点的左右孩子孩子。a为左孩子,b为右孩子。当a为-1时,没有左孩子。当b为-1时,没有右孩子。

输出:

输出一个整型,表示树的深度。

样例输入:
32 3-1 -1-1 -1
样例输出:
2
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>
#include <set>
 
using namespace std;
 
// 节点定义
class BSTNode
{
public:
    BSTNode()// 默认构造
    {
        pRight = NULL;
        pLeft = NULL;
        value = 0;
    }
    friend class LinkBST;// 允许链表类随意访问节点数据
 
private:
    int value;
    BSTNode *pRight;
    BSTNode *pLeft;
};
 
// 不带头结点的二叉树定义 
class LinkBST
{
public:
    LinkBST(int size)
    {
        m_pNode = new BSTNode[size+1];
    }
    ~LinkBST()
    {
        delete[] m_pNode;
        m_pNode = NULL;
    }
    // 连接节点集(形成一棵树)
    void LinkBSTNode(int lvlaue, int rvalue, int pos);
 
    // 计算树的深度
    int DepthTree(BSTNode *&pRoot);
 
    // 节点集
    BSTNode *m_pNode;
 
};
 
// 连接节点集(形成一棵树)
void LinkBST::LinkBSTNode(int lnode, int rnode, int pos)
{
    if (lnode != -1)
        m_pNode[pos].pLeft = &m_pNode[lnode-1];
    if (rnode != -1)
        m_pNode[pos].pRight = &m_pNode[rnode-1];
}
 
// 计算树的深度
int LinkBST::DepthTree(BSTNode *&pRoot)
{
    if (pRoot == NULL)
        return 0;
    else
        return 1 + max(DepthTree(pRoot->pLeft), DepthTree(pRoot->pRight));
}
int main()
{
    int n = 0;
    while (cin >> n)
    {
        BSTNode *pRoot = NULL;
        LinkBST bst(n);
        pRoot = &bst.m_pNode[0];//指向根节点
        int nleftnode = 0, nrightnode = 0;
        //连接节点集
        for (int i = 0; i < n; i++)
        {
            cin >> nleftnode >> nrightnode;
            if (nleftnode>n || nrightnode > n)
                exit(1);
            bst.LinkBSTNode(nleftnode, nrightnode, i);//第i个节点指向第nleftnode个节点和第nrightnode节点
        }
        cout << bst.DepthTree(pRoot) << endl;
    }
}
/**************************************************************
    Problem: 1350
    User: EbowTang
    Language: C++
    Result: Accepted
    Time:0 ms
    Memory:1520 kb
****************************************************************/





题目1351:数组中只出现一次的数字

题目描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
输入:
每个测试案例包括两行:
第一行包含一个整数n,表示数组大小。2<=n <= 10^6。
第二行包含n个整数,表示数组元素,元素均为int。
输出:
对应每个测试案例,输出数组中只出现一次的两个数。输出的数字从小到大的顺序。
样例输入:
8
2 4 3 6 3 2 5 5
样例输出:
4 6
#include <cstdio>  
#include <cstdlib>  
#include "vector"
#include "string"
#include "algorithm"
#include <iostream>
#include "stack"
#include <cmath>  
 
using namespace std;
 
int main()
{
    int  n;
    while (cin >> n && n >= 1 && n <= 1000000)
    {
        vector<int> vec(n, 0);
        for (int i = 0; i < n; i++)
            scanf("%d", &vec[i]);
        //直接排序
        sort(vec.begin(), vec.end());
        //准备获取这两个数
        vector<int> ans(2, 0);
        int k = 0;
        //直接判断首尾是否是只出现一次的数
        if (n>2 && vec[0] != vec[1])
            ans[k++] = vec[0];
        if (n>2 && vec[n - 1] != vec[n - 2])
            ans[k++] = vec[n - 1];
        //判断除去首尾后的中间数是否是只出现一次
        for (int i = 1; i < n -1; i++)
        {
            if (k == 2)
                break;
            if (vec[i] != vec[i - 1] && vec[i] != vec[i + 1])//只出现一次的充分条件
                ans[k++] = vec[i];
        }
        //按照大小输出
        if (ans[0]>ans[1])
            cout << ans[1] << " " << ans[0] << endl;
        else
            cout << ans[0] << " " << ans[1] << endl;
    }
    return 0;
}
/**************************************************************
    Problem: 1351
    User: EbowTang
    Language: C++
    Result: Wrong Answer
****************************************************************/





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值