LDU_軟件工程 算法分析與設計(二)暴力搜索

 

問題 A: 0-1揹包問題(基於暴力)

題目描述

給定一個容積爲m的揹包,去嘗試裝n個重量爲wi、價值爲vi的物體,求能裝下的物體的最大價值。

輸入

輸入的第一行有兩個整數n和m,分別表示物品的個數,揹包的最大容量。 
接下來n行,每行兩個數字,每個物品的重量w和價值v 
數據保證1<=n<=20,1<=w , v<=2000 

輸出

一個整數,表示可獲得的最大價值。

樣例輸入

3 30
16 45
15 25
15 25

樣例輸出

50

思想:裸的01揹包

#include<bits/stdc++.h>
using namespace std;
const int maxn=40005;
int dp[maxn];
 
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
    {
        int w,v;
        scanf("%d%d",&w,&v);
        for(int j=m;j>=w;j--)
            dp[j]=max(dp[j],dp[j-w]+v); 
    }
    int ans=0;
    for(int i=0;i<=m;i++)
        ans=max(ans,dp[i]);
    printf("%d\n",ans);
    return 0;
} 

問題 B: 八皇后問題(基於暴力)

題目描述

皇后問題。所謂的n皇后問題,是指在n×n的棋盤上放置彼此不受攻擊的n個皇后,按照國際象棋的規則,皇后可以攻擊與之處在同一行或同一列或同一斜線上的棋子。後問題等價於在n×n格的棋盤上放置n個皇后,任何2個皇后不放在同一行或同一列或同一斜線上。 
爲了使問題更加有趣,我們需要求在n×n的棋盤上,放置k個皇后,共有多少種可能的方案數? 

輸入

兩個正整數n和k,(n,k<=10)

輸出

一個整數,表示方案數。

樣例輸入

8 8

樣例輸出

92

思想:n*n的棋盤放k個皇后,dfs暴力加剪枝。當然可以本地打表,輸出表。

#include<bits/stdc++.h>
using namespace std;
int sum,n,k;
int Map[15];
int check(int x)
{
    for(int i=1;i<x;i++)
        if((abs(x-i)==abs(Map[x]-Map[i])) || (Map[x]==Map[i]))
            return 0;
    return 1;
}
void dfs(int id,int flag)
{
    if(id>n)
    {
        if(flag==0)
            sum++;
        return ;
    }
    else if(n-id+1 < flag)
        return ;
    for(int i=1;i<=n;i++)
    {
        Map[id]=i;
        if(check(id))
            dfs(id+1,flag-1);
    }   
    Map[id]=-1000;
    dfs(id+1,flag);
}
int main()
{
    scanf("%d%d",&n,&k);
    sum=0;
    if(n>=k)
        dfs(1,k); 
    printf("%d\n",sum);
    return 0;
} 

問題 C: 李白飲酒--藍橋杯原題改編(基於暴力)

題目描述

話說大詩人李白,一生好飲。幸好他從不開車。一天,他提着酒壺,從家裏出來,酒壺中有酒2鬥。他邊走邊唱:

無事街上走,提壺去打酒。逢店加一倍,遇花喝一斗。 

這一路上,他一共遇到店5次,遇到花10次,已知最後一次遇到的是花,他正好把酒喝光了。請你計算李白遇到店和花的次序,可以把遇店記爲a,遇花記爲b。則babaabbabbabbbb 就是合理的次序。像這樣的答案一共有多少呢?請你計算出所有可能方案的個數。 

爲了使問題更加有趣,我們假設他遇到店s次,花f次,你的任務是計算此時的方案總數。 

輸入

兩個整數s和f,分別表示李白遇到的店和花的次數。(s+f<=20)

輸出

一個整數,表示方案總數。

樣例輸入

5 10

樣例輸出

14

思想:2進制枚舉,最多2^10  

#include<bits/stdc++.h>
using namespace std;
int ans,s,f;
void dfs(int dian,int hua,int jiu,int flag)
{
    if(dian==s && hua==f && jiu==0 && flag==1)
    {
        ans++;
        return ;
    }
    if(dian<s)
        dfs(dian+1,hua,jiu*2,0);
    if(hua<f)
        dfs(dian,hua+1,jiu-1,1);
}
int main()
{
    scanf("%d%d",&s,&f);
    if(f==0)
    {
        printf("0\n");
        return 0;
    }
    ans=0;
    dfs(0,0,2,0);
    printf("%d\n",ans);
    return 0;
}

問題 D: 組素數

題目描述

素數就是不能再進行等分的數。比如:2、3、5、7、11 等。9 = 3 * 3 說明它可以3等分,因而不是素數。

我們國家在1949年建國。如果只給你 1、9、4和9 這4個數字卡片,可以隨意擺放它們的先後順序,那麼,你能組成多少個4位的素數呢? 

比如:1949,4919 都符合要求。 

爲了使問題更加有趣,我們輸入n個數字,求這n個數字可以組成的數字中的素數。 

輸入

第一行一個整數n。(n<=6)
第二行n個空格分隔的整數,僅包含1~9 

輸出

輸出所有符合的素數。若沒有可行解,則輸出-1。

樣例輸入

4
1 9 4 9

樣例輸出

1499
1949
4919
9419
9491
9941

思想:1e6素數打表,然後全排列一下判斷素數就行了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int a[10];
int vis[maxn];
void init()
{
    for(int i=4;i<maxn;i+=2)
        vis[i]=1;
    for(int i=3;i<maxn;i++)
    {
        if(vis[i]==0)
        {
            for(int j=i+i;j<maxn;j+=i)
                vis[j]=1;
        }
    }       
}
int main()
{
    init();
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    sort(a,a+n);
    int flag=0;
    int ans=0;
    do{
        int Ans=0;
        for(int i=0;i<n;i++)
            Ans=Ans*10+a[i];
        if(vis[Ans]==0)
        {
            flag=1;
            printf("%d\n",Ans);
        }
    }while(next_permutation(a,a+n));
    if(flag==0)
        printf("-1\n");
    return 0;
}

問題 E: 匪警110問題

題目描述

匪警請撥110,即使手機欠費也可撥通!爲了保障社會秩序,保護人民羣衆生命財產安全,警察叔叔需要與罪犯鬥智鬥勇,因而需要經常性地進行體力訓練和智力訓練! 
某批警察叔叔正在進行智力訓練: 
12 3 4 5 6 7 8 9 = 110 
    請看上邊的算式,爲了使等式成立,需要在數字間填入加號或者減號(可以不填,但不能填入其它符號)。之間沒有填入符號的數字組合成一個數,例如:12+34+56+7-8+9 就是一種合格的填法;123+4+5+67-89 是另一個可能的答案。 
    請你利用計算機的優勢,幫助警察叔叔快速找到所有答案。形如: 
12+34+56+7-8+9 
123+4+5+67-89 
.... 
爲了使問題更加有趣,我們把後面的數字110換成n。注意:這裏只要求你計算方案數。不必輸出每種方案。 

輸入
一個整數n,如題所述。(-2000000000<=n<=2000000000) 

輸出

一個整數,表示方案數。

樣例輸入

110

樣例輸出

10

思想:三進制枚舉下,考慮當前放什麼。3^8

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[10]={1,2,3,4,5,6,7,8,9};
    int ans=0;
    int n;
    scanf("%d",&n);
    int m=(int)pow(3,8);
    for(int i=0;i<m;i++)
    {
        int TT=1,sum=0;
        int temp=i;
        int op=1;
        for(int j=1;j<9;j++)
        {
            if(temp%3==0)
                TT=TT*10+a[j];
            else if(temp%3==1)
            {
                if(op==1)
                {
                    sum+=TT;
                    TT=a[j]; 
                }
                else
                {
                    sum-=TT;
                    TT=a[j];
                }
                op=1;   
            }
            else
            {
                if(op==1)
                {
                    sum+=TT;
                    TT=a[j]; 
                }
                else
                {
                    sum-=TT;
                    TT=a[j];
                }
                op=2;   
            }
            temp/=3;    
        }
        if(op==1)
            sum+=TT;
        else
            sum-=TT;
        if(sum==n)
            ans++; 
    }
    printf("%d\n",ans);
    return 0;
}

問題 F: 敢死隊

題目描述

G將軍有一支訓練有素的軍隊,這個軍隊除了G將軍外,每名士兵都有一個直接上級(可能是其他士兵,也可能是G將軍)。現在G將軍將接受一個特別的任務,需要派遣一部分士兵(至少一個)組成一個敢死隊,爲了增加敢死隊隊員的獨立性,要求如果一名士兵在敢死隊中,他的直接上級不能在敢死隊中。請問,G將軍有多少種派出敢死隊的方法。注意,G將軍也可以作爲一個士兵進入敢死隊。 

輸入

   輸入的第一行包含一個整數n(1<=n<=1000),表示包括G將軍在內的軍隊的人數。軍隊的士兵從1至n編號,G將軍編號爲1。接下來n-1個數,分別表示編號爲2, 3, ..., n的士兵的直接上級編號,編號i的士兵的直接上級的編號小於i。

輸出

一個整數,表示方法數。注意:答案可能會很大,可能不足以64位整數存儲,因此你需要輸出模除1000000007後的結果。

樣例輸入

4
1 2 3

樣例輸出

7

思想:樹形DP,考慮子孩子對於父親節點的影響,如果當前不去,那麼他的子孩子都可以,如果當前去,他的子孩子都不能去。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
typedef long long ll;
const ll mod = 1e9+7; 
ll dp[maxn][2];
vector<int>V[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        int fa;
        scanf("%d",&fa);
        V[fa].push_back(i);
    } 
    for(int i=n;i>=1;i--)
    {
        dp[i][0]=dp[i][1]=1ll;
        for(int j=0;j<V[i].size();j++)
        {
            //printf("~%lld %lld\n",dp[V[i][j]][0],dp[V[i][j]][1]);
            dp[i][0]=(dp[i][0]%mod*(dp[V[i][j]][0]+dp[V[i][j]][1])%mod)%mod;
            dp[i][1]=(dp[i][1]%mod*dp[V[i][j]][0]%mod)%mod;
            //printf("%lld %lld\n",dp[i][0],dp[i][1]);  
        }
    }
    printf("%lld\n",(dp[1][0]+dp[1][1]-1ll)%mod);
    return 0;
}

問題 G: 獨立任務最優調度問題

題目描述

用兩臺處理機A和B處理n個作業。設第i個作業交給A處理需要時間ai,交給B處理需要時間bi。由於各作業的特點和機器的性能關係,ai和bi之間沒有明確的大小關係。既不有將一個作業分開由2臺機器處理,也沒有一臺機器能同時處理2個作業。設計一個算法,使得這兩臺機器處理完這n個作業的時間最短。

輸入

第一行一個整數n,表示任務數(1<=n<=20)。 
第二行n個整數,分別表示第i個任務在機器A上的處理時間。 
第三行n個整數,分別表示第i個任務在機器B上的處理時間。

處理時間數據範圍(1~40) 

輸出

一個整數,表示最少的完成這些任務的時間 。

樣例輸入

3
1 4 7
2 5 8

樣例輸出

7

思想:直接2進制枚舉情況取一個最小的即可。2^20 。

或者可以考慮下DP     dp[i][j]表示第i個任務,A機器花費了j時間。dp[i][j]=min(dp[i-1][j]+b[i],dp[i-1][j-a[i])

枚舉:

#include<bits/stdc++.h>
using namespace std;
int a[25];
int b[25];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<n;i++)
        scanf("%d",&b[i]);
    int m=(int)pow(2,n);
    int ans=1<<30;
    for(int i=0;i<=m;i++)
    {
        int temp=i;
        int sum1=0;
        int sum2=0;
        for(int j=0;j<n;j++)
        {
            if(temp%2==0)
                sum1+=a[j];
            else
                sum2+=b[j];
            temp=temp/2;
        }
        temp=max(sum1,sum2);
        ans=min(ans,temp);
    }
    printf("%d\n",ans);
    return 0;
}

DP

#include<bits/stdc++.h>
using namespace std;
int a[25];
int b[25];
int dp[25][1000];
int main()
{
    int n,sum=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    for(int i=0;i<n;i++)
        scanf("%d",&b[i]);
     
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=sum;j++)
        {
            if(j<a[i-1])//A不夠做這個任務 
                dp[i][j] = dp[i-1][j]+b[i-1];
            else if(dp[i-1][j]+b[i-1]<dp[i-1][j-a[i-1]])
                dp[i][j] = dp[i-1][j]+b[i-1];
            else
                dp[i][j] = dp[i-1][j-a[i-1]];       
        }       
    }
    int Max=1<<30;
    for(int i=0;i<=sum;i++)
        Max=min(Max,(max(dp[n][i],i)));
    printf("%d\n",Max);
    return 0;
} 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章