T1442 小木棍(信息學奧賽一本通)

【問題】

喬治有一些同樣長的小木棍,他把這些木棍隨意砍成幾段,直到每段的長都不超過50。現在,他想把小木棍拼接成原來的樣子,但是卻忘記了自己開始時有多少根木棍和它們的長度。給出每段小木棍的長度,編程幫他找出原始木棍的最小可能長度。

【輸入】

第一行爲一個單獨的整數N表示砍過以後的小木棍的總數,其中N≤60,第二行爲N個用空個隔開的正整數,表示N根小木棍的長度。

【輸出】

僅一行,表示要求的原始木棍的最小可能長度。

【源代碼】

不知道爲啥這個代碼在信息學奧賽一本通網站上過不了

#include<bits/stdc++.h>
using namespace std;
const int N = 70;
int n,sum,len,tot;
int a[N],vis[N];
bool cmp(int u,int v)
{
    return u > v ;
}
// 第k根,還需要now的長度,枚舉第pos根木棍
bool dfs(int k,int now,int pos)
{
    if(k == tot + 1) return true; //已經拼完了前tot根,所以返回答案
    if(now == 0)
    {
        // 如果當前木棍已經拼接好,接着拼下一根,直到拼完tot根爲止
        return dfs(k+1,len,1);
    }
    // 剪枝2,如果當前用了第i個,則從i+1根開始拼
    for(int i=pos; i<=n; i++)
    {
        if(!vis[i] && a[i]<=now)      // 選擇當前木棍,必須是沒選中過,同時適合拼接下去
        {
            vis[i] = 1 ;
            if(dfs(k,now-a[i],i+1)) return true;
            vis[i] = 0 ;
            if(now == len || now == a[i]) //如果拼不出來直接返回,原因是不可能再繼續下去
                return false;
            while(a[i] == a[i+1]) i++;    //相同長度不要多次搜索
        }
    }
    return false;
}
int main()
{
    cin >> n;
    for(int i=1; i<=n; i++)
    {
        cin >> a[i];
        sum += a[i] ;
    }
    sort(a+1,a+1+n,cmp );
    for(int i=a[1]; i<=sum; i++)
    {
        if(sum%i==0)
        {
            memset(vis,0,sizeof vis) ;
            len = i ;           // 設爲全局變量,木棍的長度
            tot = sum/i;        // 木棍的數目
            if(dfs(1,len,1))
            {
                cout << len <<endl;
                return 0;
            }
        }
    }
    return 0;
}

AC代碼

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
const int N = 1000+5;
using namespace std;
int a[N];
bool vis[N];
int cnt;
bool cmp(int x,int y){ return x>y; }
bool dfs(int k,int step,int rest,int len){
//k爲已經拼接好的個數,step爲上一個的編號,rest爲剩餘的長度,len爲木棍的長度
    if(k==cnt+1 && rest==0)//拼接好個數爲要求數且無剩餘
        return true;
    else if(k==cnt+1)//拼接好個數爲要求數但有剩餘
        return false;
    else if(rest==0){//拼接好個數不爲要求數但無剩餘,重新開始
        rest=len;//剩餘數變爲長度
        step=0;//編號歸零
    }
    for(int i=step+1;i<=cnt;i++){
        if(!vis[i]){
            if(rest-a[i]>=0){//保證剩餘值不爲負數
                vis[i]=true;
                if(dfs(k+1,i,rest-a[i],len))
                    return true;
                vis[i]=false;
                if(a[i]==rest || len==rest)//頭尾剪枝,此時已在回溯之後,需要判斷頭尾兩種情況
                    break;
                while(a[i]==a[i+1])//去重剪枝,用當前長度搜索無結果時,對同樣長度的可以忽略
                    i++;
            }
        }
    }
    return 0;
}
int main(){
    int n;
    cin >> n;
    int sum=0;
    for(int i=1;i<=n;i++){
        int x;
        cin >> x;
        if(x<=50){
            a[++cnt]=x;
            sum+=x;
        }
    }
    sort(a+1,a+1+cnt,cmp);
    for(int i=a[1];i<=sum;i++){
        if(sum%i==0){
            if(dfs(1,0,i,i)){
                cout << i <<endl;
                break;
            }
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章