POJ-1002 解题报告

 

1.题目描述

http://poj.org/problem?id=1002

2.解题过程

按部就班来解题的话,这个题目很容易写出来,这是我的第一个版本的代码,思路是读入一行电话字符串,均转化为整型数字存入vector结构,然后进行排序,顺序统计即可发现重复的电话号码及次数。

   1: /*author :lipan
   2:   date: 2013.7.23
   3:   email: areslipan@163.com
   4:  */
   5:  
   6: #include <iostream>
   7: #include <vector>
   8: #include <iterator>
   9: #include <string>
  10: #include <algorithm>
  11:  
  12: using namespace std;
  13:  
  14: int cvtString2Int(string & str);
  15: void normalizedOutput(int tel,int &count);
  16: void showDump(vector<int> & telNum);
  17:  
  18: bool sortAsc(const int & v1 ,const int & v2)
  19: {
  20:     return v1<v2;
  21: }
  22: /*
  23: void showIntVector(vector<int> & in)
  24: {
  25:     vector<int>::iterator iter;
  26:     cout<<endl;
  27:     for(iter = in.begin(); iter!= in.end();++iter)
  28:     {
  29:         cout<< *iter<<endl;
  30:     }
  31: }*/
  32: int main()
  33: {
  34:     int count;
  35:  
  36:     vector<int> input_tel;
  37:  
  38:     cin>>count;
  39:  
  40:     string curTel;
  41:     int curTelInt;
  42:     for(int i=0;i<count;++i)
  43:     {
  44:         cin>> curTel;
  45:         input_tel.push_back(cvtString2Int(curTel));
  46:  
  47:     }
  48:   
sort(input_tel.begin(),input_tel.end(),sortAsc);
  49:     //showIntVector(input_tel);
  50:     showDump(input_tel);
  51:     return 1;
  52: }
  53:  
  54: int cvtString2Int(string & str)
  55: {
  56:     int ret = 0;
  57:     for(int i = 0; i< str.length(); ++i)
  58:     {
  59:         if(str[i] == '-') continue;
  60:         
  61:         int digit;
  62:         if(str[i]>='0'&&str[i]<='9')
  63:         {
  64:             digit = str[i] - '0';
  65:         }
  66:         else
  67:         {
  68:             if (str[i] <'Z' &&str[i]>'Q')
  69:             {
  70:                 digit = (str[i] - 'Q')/3 + 7;
  71:             }
  72:             else
  73:                 if(str[i]>='A' &&str[i]<'Q')
  74:                 {
  75:                     digit = (str[i] - 'A')/3 + 2;
  76:                 }
  77:         }
  78:  
  79:         ret = 10 * ret + digit;
  80:  
  81:     }    
  82:  
  83:     return ret;
  84: }
  85:  
  86: void normalizedOutput(int tel,int &count)
  87: {
  88:     cout<<endl;
  89:     vector<int> result;
  90:     int bitNum  = 0;
  91:     while(tel!=0)
  92:     {
  93:         result.push_back(tel%10);
  94:         tel /=10;
  95:         bitNum ++;
  96:     }
  97:  
  98:     int hy = 0;
  99:     while(bitNum<7)
 100:     {
 101:         cout << '0';
 102:         hy++;
 103:         if(hy == 3)cout << '-';
 104:         bitNum ++;
 105:     }
 106:  
 107:     vector<int>::reverse_iterator  iter;
 108:     for(iter = result.rbegin();iter!= result.rend();++iter)
 109:     {
 110:         cout<<*iter;
 111:         hy++;
 112:         if(hy == 3)cout<<'-';
 113:     }
 114:  
 115:     cout<<" "<<count;
 116:     
 117: }
 118: void showDump(vector<int> & telNum)
 119: {
 120:     int flag = 0;
 121:     int count = 1;
 122:  
 123:     vector<int>::iterator iter;
 124:  
 125:     int  curTel  = -1;
 126:     for(iter = telNum.begin(); iter != telNum.end(); ++iter)
 127:     {
 128:         if(curTel == *iter){count ++;}
 129:         else
 130:         {
 131:             if(count>1)
 132:             {
 133:                 normalizedOutput(curTel ,count);
 134:                 count = 1;
 135:                 curTel = *iter;
 136:                 if(flag == 0 ) flag = 1;
 137:             }
 138:             else
 139:             {
 140:                 curTel = *iter;
 141:             }
 142:         }
 143:     }
 144:  
 145:     if(count >1)
 146:     {
 147:         normalizedOutput(curTel,count);
 148:         if(flag == 0 )flag = 1;
 149:     }
 150:  
 151:     if (flag == 0)
 152:     {
 153:         cout<<"No duplicates.";
 154:     }
 155: }

在数据量较小时,这种解法没有问题,但是一旦输入数据变多,程序的效率就会出现大问题,比如这个用这个代码在提交online judge的时候就出现了”Time Limit Exceeded”错误,最开始以为,程序运行效率的瓶颈在于这句话,众所周知,目前排序算法的效率最好也只有O(NlgN),本题最大输入数目为100000,在极端情况下效率是不行的。

sort(input_tel.begin(),input_tel.end(),sortAsc);

但是,本着实事求是的态度,我在机器上测了一下这句话的运行时间,测试方法如下(在main函数中加入时间戳):

   1: int main()
   2: {
   3:     int count;
   4:  
   5:     vector<int> input_tel;
   6:  
   7:     cin>>count;
   8:  
   9:     string curTel;
  10:     int curTelInt;
  11:     for(int i=0;i<count;++i)
  12:     {
  13:         cin>> curTel;
  14:         input_tel.push_back(cvtString2Int(curTel));
  15:  
  16:     }
  17:     clock_t start, finish;
  18:     start  = clock();
  19:  
  20:     sort(input_tel.begin(),input_tel.end(),sortAsc);
  21:  
  22:     finish = clock();
  23:  
  24:     cout<<"time eclapse: " <<start<<"/"<<finish<<"/"<<(double)(finish-start)<<"/"<<(double)(finish-start)/CLOCKS_PER_SEC <<endl;
  25:     
  26:     //showIntVector(input_tel);
  27:     showDump(input_tel);
  28:  
  29:     finish = clock();
  30:  
  31:     cout<<"time eclapse: " <<start<<"/"<<finish<<"/"<<(double)(finish-start)<<"/"<<(double)(finish-start)/CLOCKS_PER_SEC <<endl;
  32:     return 1;
  33: }

 

得到的结果大大出乎我的意料,我用73728个数据进行极端测试,结果发现,排序所用时间其实很短,下面是运行结果

image

可以看到,实际上排序只花了21毫秒,很快就完成了。

那么究竟出了什么问题?

仔细分析觉得可能是online judge把我的输入时间算在总时间里面了,这样的话cin的效率必须考虑,网上搜了一下,发现C++和G++在cin的效率上差别还蛮大的,于是编译器改成了C++,这样一来竟然直接就AC了,汗~(因为程序我是在minGW中调试的,所以submit的时候我一直选G++)。

一般提交时,对于c++程序,用G++或者C++,根据poj中FAQ的描述:

image

VC++中很多细节实现和C++标准不一样,因此,可以想见,VC++中cin的实现更有效率些或者cin的配置更有效率些。

有了这个想法,就在网上搜索相关资料,发现,其实在G++中也有方式能够使得cin的效率提高,只需在程序开头配置一下就好了,如下:

   1: std::ios::sync_with_stdio(false);

 

具体原因在探寻C++最快的读取文件的方案 中有解释,大概意思就是“对于G++,默认的时候,cin与stdin总是保持同步的,也就是说这两种方法可以混用,而不必担心文件指针混乱,同时cout和stdout也一样,两者混用不会输出顺序错乱。正因为这个兼容性的特性,导致cin有许多额外的开销,如何禁用这个特性呢?只需刚才的语句即可”。总之,VC对cin取消同步与否不敏感,前后效率相同。反过来MINGW则非常敏感,前后效率相差8倍

一般来讲,linux程序会比window上的程序效率高一点,在用G++和C++都能AC过之后,

image

发现,同样的程序,时间效率上G++要高很多。这也是一个以后需要注意的问题。

程序写得略长,实际上有些小改进,比如说normlizedoutput函数可以如下改进:

void normalizedOutput(int & tel,int &count)
{
    cout<<tel/1000000<<tel/100000%10<<tel/10000%10<<"-";  
    cout<<tel/1000%10<<tel/100%10<<tel/10%10<<tel%10<<" "<<count<<endl; 
}
//或者直接写入showDump函数中,毕竟调用函数也有开销。

这么一改进之后,程序效率进一步提高,

image

最终程序如下:

/*author :lipan
  date: 2013.7.23
  email: areslipan@163.com
 */
 
#include <iostream>
#include <vector>
#include <iterator>
#include <string>
#include <algorithm>
using namespace std;
 
int cvtString2Int(string & str);
void normalizedOutput(int &tel,int &count);
void showDump(vector<int> & telNum);
 
bool sortAsc(const int & v1 ,const int & v2)
{
    return v1<v2;
}
 
int main()
{
    int count;
 
    vector<int> input_tel;
    std::ios::sync_with_stdio(false);
    cin>>count;
 
    string curTel;
    int curTelInt;
    for(int i=0;i<count;++i)
    {
        cin>> curTel;
        input_tel.push_back(cvtString2Int(curTel));
 
    }
    
 
    sort(input_tel.begin(),input_tel.end(),sortAsc);
 
    showDump(input_tel);
    return 1;
}
 
int cvtString2Int(string & str)
{
    int ret = 0;
    for(int i = 0; i< str.length(); ++i)
    {
        if(str[i] == '-') continue;
        
        int digit;
        if(str[i]>='0'&&str[i]<='9')
        {
            digit = str[i] - '0';
        }
        else
        {
            if (str[i] <'Z' &&str[i]>'Q')
            {
                digit = (str[i] - 'Q')/3 + 7;
            }
            else
                if(str[i]>='A' &&str[i]<'Q')
                {
                    digit = (str[i] - 'A')/3 + 2;
                }
        }
 
        ret = 10 * ret + digit;
 
    }    
 
    return ret;
}
 
/*
void normalizedOutput(int &tel,int &count)
{
    vector<int> result;
    int bitNum  = 0;
    while(tel!=0)
    {
        result.push_back(tel%10);
        tel /=10;
        bitNum ++;
    }


    int hy = 0;
    while(bitNum<7)
    {
        cout << '0';
        hy++;
        if(hy == 3)cout << '-';
        bitNum ++;
    }


    vector<int>::reverse_iterator  iter;
    for(iter = result.rbegin();iter!= result.rend();++iter)
    {
        cout<<*iter;
        hy++;
        if(hy == 3)cout<<'-';
    }


    cout<<" "<<count<<endl;


}*/
 
void normalizedOutput(int & tel,int &count)
{
    cout<<tel/1000000<<tel/100000%10<<tel/10000%10<<"-";  
    cout<<tel/1000%10<<tel/100%10<<tel/10%10<<tel%10<<" "<<count<<endl; 
}
void showDump(vector<int> & telNum)
{
    int flag = 0;
    int count = 1;
 
    vector<int>::iterator iter;
 
    int  curTel  = -1;
    for(iter = telNum.begin(); iter != telNum.end(); ++iter)
    {
        if(curTel == *iter){count ++;}
        else
        {
            if(count>1)
            {
                normalizedOutput(curTel ,count);
                count = 1;
                curTel = *iter;
                if(flag == 0 ) flag = 1;
            }
            else
            {
                curTel = *iter;
            }
        }
    }
 
    if(count >1)
    {
        normalizedOutput(curTel,count);
        if(flag == 0 )flag = 1;
    }
 
    if (flag == 0)
    {
        cout<<"No duplicates.";
    }
}
posted @ 2013-07-24 16:17  曾见绝美的阳光  阅读(702)  评论(0编辑  收藏  举报