前言
這道題理解起來不難,但是要找到一個合適的方法對題目進行優化,就會相對麻煩些。
藍橋杯的題,真的到處都是坑的感覺。。。
帶分數題目
資源限制
時間限制:1.0s 內存限制:256.0MB
問題描述
100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714。
還可以表示爲:100 = 82 + 3546 / 197。
注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。
類似這樣的帶分數,100 有 11 種表示法。
輸入格式
從標準輸入讀入一個正整數N (N<1000*1000)
輸出格式
程序輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。
注意:不要求輸出每個表示,只統計有多少表示法!
樣例輸入1
100
樣例輸出1
11
樣例輸入2
105
樣例輸出2
6
題目分析
①、帶分數中,數字1~9分別出現且只出現一次(不包含0)。
②、100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714。
解題思路
①:如何實現在帶分數中,數字1~9分別出現且只出現一次。我們可以考慮全排列,將每種排列都來一遍(感覺挺麻煩的,如果有更好的方法歡迎留言討論)。
②:在例子中 100 = 3 + 69258 / 714,“3 + 69258 / 714”部分要符合數字1~9分別出現且只出現一次,這時可以用到我們字符串截取。拿上面的例子說,排列爲369258714,我們截取了字符串3、字符串69258、字符串714,然後將三個字符串轉換爲int類型變量,看看是否符合條件(100 = 3 + 69258 / 714)符合則記錄下來。
實用工具功能及使用
實現全排列:next_permutation(s.begin(), s.end());
在C++中,在字符串要有序的前提下,我們能使用現成的函數完成字符串的全排列。例如:string s=“123456789”;,字符串s已經有序。通過 while(next_permutation(s.begin(), s.end())); 不斷將s進行全排序,當s的全排序全部排完後,跳出循環。可能你會覺得這個有什麼用?讓我們帶着這個問題看看代碼設計吧!
string s="123456789";
do
{
....
}
while(next_permutation(s.begin(), s.end()));
我們這裏用do-while的循環體,保證s每進行一次全排列就會先進行do包含的語句。
實現字符串截取:string a = s.substr(i,len);
在s字符串中,從下標爲i的位置,向右截取len長度的字符串,得到a字符串。
實現字符串轉換爲int類型變量:int a = atoi(s.c_str);
將字符串s轉換爲int類型變量a。
代碼實現
代碼一
通過我們的解題思路和工具結合,我們可以得到以下代碼一。
//全排列 next_permutation(s.begin(),s.end())
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;
int main()
{
// clock_t start, finish;
// start = clock();
int n;
string s="123456789";
// sort(s,s+9);
cin>>n;
do
{
for(int i=1; i<=7; i++)
{
string a=s.substr(0,i);
int inta=atoi(a.c_str());
if(inta>=n) break;
for(int j=1; j<=8-i; j++)
{
string b=s.substr(i, j);
int intb=atoi(b.c_str());
string c=s.substr(j+i);
int intc=atoi(c.c_str());
if(intb%intc==0&&inta+intb/intc==n)
ans++;
}
}
}
//使用next_permutation前要先排序
while(next_permutation(s.begin(), s.end()));
cout<<ans;
// finish = clock();
// double _time = (double)(finish - start) / CLOCKS_PER_SEC;
// printf("\ntime:%llf", _time);
return 0;
}
好啦,恭喜你答對了題目一半,爲什麼是一半呢?因爲如果你拿去評測的話, 你會發現:運行超時!
下面是代碼二在N=100條件下的運行時間time (單位秒)
原因:substr函數返回的是值(而不是引用或指針) 在多次調用中傳遞了大量對象(而不是引用或指針) 導致了耗時多。
在代碼裏,substr函數被放在內層循環中,被調用的次數很多,這樣的對程序運行總時間的影響就增大了,拖慢了程序運行速度。
代碼二(手寫截取字符串,引用字符串s)
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;
int parse(string &s, int a, int b)//字符串轉換爲int類型
{
int temp=0;
for(int i=a; i<b; i++)
{
temp+=s[i]-'0';
if(i<b-1)
temp*=10;
}
return temp;
}
int main()
{
// clock_t start, finish;
// start = clock();
int N;
string s="123456789";
// sort(s,s+9);
cin>>N;
do
{// 1234567+8/9
for(int i=1; i<=7; i++) //分割第一個數據長度
{
int inta = parse(s, 0, i);
if(inta>N) break;
//1+2345678/9
//12+345678/9
//1+2/3456789
for(int j=1; j<=8-i; j++) //分割第二個數據長度
{
int intb=parse(s, i, j+i);
int intc=parse(s, j+i, s.length());//分割第三個數據
if(intb%intc==0&&inta+intb/intc==N)
{
// cout<<inta<<"+"<<intb<<"/"<<intc<<endl;
ans++;
}
}
}
}
while(next_permutation(s.begin(), s.end()));
cout<<ans;
// finish = clock();
// double _time = (double)(finish - start) / CLOCKS_PER_SEC;
// printf("\ntime:%llf", _time);
return 0;
}
優化:截取字符串函數傳參採用傳指針或引用(即在parse 的string參數右側加一個&)。
下面是代碼二在N=100條件下的運行時間time (單位秒)
時間上滿足1s內,可以通過評測。
下面還能夠再通過優化算法的方式,進一步縮短運行時間。
代碼三(算法優化)
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
ll ans=0;
int parse(string& s, int a, int b)//字符串轉換爲int類型
{
int temp=0;
for(int i=a; i<b; i++)
{
temp+=s[i]-'0';
if(i<b-1)
temp*=10;
}
return temp;
}
int main()
{
// clock_t start, finish;
// start = clock();
int N;
string s="123456789";
// sort(s,s+9);
// N=100;
cin>>N;
do
{
for(int i=1; i<=7; i++)
{
int inta = parse(s, 0, i);
if(inta>N) break;
//1+2345678/9
//12+345678/9
//1+2/3456789
for(int j=1; j<=8-i; j++)
{
if(j<9-i-j) continue; //排除多餘情況
int intb=parse(s, i, j+i);
int intc=parse(s, j+i, s.length());
if(intb%intc==0&&inta+intb/intc==N)
{
// cout<<inta<<"+"<<intb<<"/"<<intc<<endl;
ans++;
}
}
}
}
while(next_permutation(s.begin(), s.end()));
cout<<ans;
// finish = clock();
// double _time = (double)(finish - start) / CLOCKS_PER_SEC;
// printf("\ntime:%llf", _time);
return 0;
}
優化:排除多餘判斷情況。
下面是代碼三在N=100條件下的運行時間time(單位秒)
總結
這道題思路固然重要,但是優化也很重要。
在藍橋杯的比賽中,都是提交代碼,我們不能都提前判斷我們的代碼是否能夠通過所有評測數據,所以要儘量將時間複雜度降到最小。
感謝評論區的朋友,對我的文章提出指正√
希望能夠將自己的一些學習經驗分享給有需要的人。
我是小鄭,一個堅持不懈的小白。