1. 程式人生 > >LDU軟體工程演算法課程習題(二)

LDU軟體工程演算法課程習題(二)

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

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 39  解決: 27 [提交] [狀態] [討論版] [命題人:admin]

題目描述

給定一個容積為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 = 2e3+10;
int v[maxn],w[maxn];
int dp[maxn*100];
int main()
{
	int n,back;
	scanf("%d%d",&n,&back);
	for(int i = 0;i < n;i++)
		scanf("%d%d",w+i,v+i);
	dp[0] = 0;
	for(int i = 0;i < n;i++)
	{
		for(int j = back;j >= w[i];j--)
		{
			dp[j] = max(dp[j],dp[j-w[i]]+v[i]);
		}	
	}
	printf("%d\n",dp[back]);
	return 0;
}

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

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 54  解決: 13 [提交] [狀態] [討論版] [命題人:admin]

題目描述

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

輸入

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

輸出

一個整數,表示方案數。

樣例輸入

8 8

樣例輸出

92

思路:這是一個n*n棋盤的k皇后問題,相比於n皇后問題我們可以不放皇后,所以dfs的過程中從0開始放表示不放。

#include<bits/stdc++.h>
using namespace std;
int cow[15];
int ans = 0;
int curzero;
int flag;
int n,k;
bool isgood(int x)
{
	if(cow[x] == 0 && curzero == n-k)
		return false;
	if(cow[x] == 0)
	return true;
	for(int i = 1;i < x;i++)
	{
		if(cow[i] != 0)
		{
			if(abs(i-x) == abs(cow[i]-cow[x]) || cow[i] == cow[x])
			return false;
		}
	}
	return true;
}
void dfs(int t)
{
	if(flag == k)
	{
		ans++;
		return ;
	}	
	if(t > n)
	return;
		for(int i = 0;i <= n;i++)
		{
			cow[t] = i; 
			if(isgood(t))
			{
				//cout<<i<<" "<<flag<<" "<<t<<endl;
				if(i == 0)
				curzero++;
				else
				flag++;
				dfs(t+1);
				if(i == 0)
				curzero--;
				else
				flag--;
			}
		
		}
}
int main()
{

	scanf("%d%d",&n,&k);
	if(n == 0 || k == 0)
	{
		printf("0\n");
		return 0;
	}
	curzero = 0;flag = 0;
	dfs(1);
	printf("%d\n",ans);
	
}

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

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 24  解決: 21 [提交] [狀態] [討論版] [命題人:admin]

題目描述

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

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

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

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

輸入

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

輸出

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

樣例輸入

5 10

樣例輸出

14

思路:李白飲酒暴力每一種情況然後檢查

#include<bits/stdc++.h>
using namespace std;

int main()
{
	int s,f;
	scanf("%d%d",&s,&f);
	int two[25] = {0,1,0,1,1,0,0,1,0,0,1,0,0,0,0};
	int temp = (1 << (s+f));
	int start,flower,drink,cnt;
	int ans = 0;
	for(int i = 0;i <= temp;i++)
	{
		start = 0,flower = 0,drink = 2,cnt = s+f;
		memset(two,0,sizeof(two));
		int number = i;
		while(number)
		{
			two[cnt--] = number%2;
			number/=2;
		}
		for(int j = 1;j <=(s+f);j++)
		{
			if(two[j] == 1)
			{
				start++;
				drink *= 2;
			}
			if(two[j] == 0)
			{
				flower++;
				drink -= 1;
			}
		}
		if(start == s && flower == f && drink == 0 && two[s+f]!=1)
			ans++;
	}
	printf("%d\n",ans);
	return 0;
}

問題 D: 組素數

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 37  解決: 14 [提交] [狀態] [討論版] [命題人:admin]

題目描述

素數就是不能再進行等分的數。比如: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

樣例輸出 1949 4919 9419 9491 9941

思路:全排列然後判斷是否是素數

#include <stdio.h>
#include<math.h> 
#define M 999999
int a[M]={0};
int n;
int count=0;
 void perm(int start,int num[]){
    int i, temp;
    int flag=1;
    int sum=0;
    if(start== n-1){  
    count++;
    int i;
    for(i = 0; i < n; ++i)
    {
    	sum+=num[i]*pow(10,n-1-i);
	}
	a[sum]++;
	for(int j=2;j<sqrt(sum);j++)
	{
		if(sum%j==0)
		{
			flag=0;
			break;
		}
	}
	if(a[sum]==1&&flag)
	  	printf("%d \n",sum);
	  else
	  {
	  	count--;
		  return ;
	  }
      
    }
    int temp1;
        for(i = start;i <n;i++){
        	
			
            temp1=num[start];
			num[start]=num[i];
			num[i]=temp1;
            perm(start + 1,num);
            temp1=num[start];
			num[start]=num[i];
			num[i]=temp1;
            
			
		}
		return;
}

int main(){
    scanf("%d",&n);
    int num[n];
   
    for(int i = 0; i < n; i++){
        scanf("%d",&num[i]);
    }
    int temp;
    for(int k=0;k<n;k++)
    {
    	for(int i=0;i<n-k-1;i++)
    	{
    		if(num[i]>num[i+1])
    		{
    			temp=num[i];
    			num[i]=num[i+1];
    			num[i+1]=temp;
			}
		}
	}
    perm(0,num);
    if(count==0)
    {
    	printf("-1");
	}
    return 0;
}
 

問題 E: 匪警110問題

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 22  解決: 17 [提交] [狀態] [討論版] [命題人:admin]

題目描述

匪警請撥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

思路:三進位制列舉每一種情況然後判斷

#include<bits/stdc++.h>
using namespace std;
int number[10] = {1,2,3,4,5,6,7,8,9};
int pp[10];
int qow(int x,int y)
{
	int res = 1;
	while(y)
	{
		if(y&1)
		res *= x;
		x *= x;
		y/=2;
	}
	return res;
 } 
int main()
{
	int n;scanf("%d",&n);
	int ans = 0;
	int temp = qow(3,8);
	for(int i = 0;i < temp;i++)
	{
		memset(pp,0,sizeof(pp));
		int res = 0;
		int now = i;
		int l = 0,pre;
		int cnt = 0;
		for(int j = 0;j < 8;j++)
		{
			pp[cnt++] = now%3;
			now /= 3;
		}
		
		int j =0;
		l = number[0];
		while(pp[j] == 0 && j < 8)
		{
			l = l*10+number[j+1];
			j++;
		}
		res += l;
		pre = pp[j];
		l = number[j+1];
		for(int k = j+1;k < 8;k++)
		{
			while(pp[k] == 0 && k < 8)
			{
				l = l*10+number[k+1];
				k++;
			}
			if(pre == 1)
			{
				res += l;
				pre = pp[k];
				l = number[k+1];
			}
			else
			{
				res -= l;
				pre = pp[k];
				l = number[k+1];
			}
			
		}
		if(pre == 1)
		res += l;
		if(pre == 2)
		res -= l;
		if(res == n)
		ans++;		
	}
	printf("%d\n",ans);
	return 0;
}

問題 F: 敢死隊

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 24  解決: 19 [提交] [狀態] [討論版] [命題人:admin]

題目描述

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

輸入

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

輸出

一個整數,表示方法數

樣例輸入

4
1 2 3

樣例輸出

7

思路:稍有難度,樹形dp,從最後面開始,因為第i個士兵的上司一定是i之前的一個人,所以從後面開始,如果此人去 那麼就要乘上後面的人不去也就是下級的情況,如果此人不去那麼要乘上下級去或者不去即兩種情況加起來的情況

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int dp[1050][2];
vector <int> person[1050];
int main()
{
	int n,x;
	scanf("%d",&n);
	for(int i = 2;i <= n;i++)
	{
		scanf("%d",&x);
		person[x].push_back(i);
	}
	int cur;
	for(int i = n;i >= 1;i--)
	{
		dp[i][0] = 1,dp[i][1] = 1;
		cur = person[i].size();
		for(int j = 0;j < cur;j++)
		{
			dp[i][0] = dp[i][0]%mod*(dp[person[i][j]][0]+dp[person[i][j]][1])%mod;
			dp[i][1] = dp[i][1]%mod*dp[person[i][j]][0]%mod;
		}
	}
	int ans = (dp[1][0]+dp[1][1]-1+mod)%mod;
	printf("%d\n",ans);
	return 0;
}

問題 G: 獨立任務最優排程問題

時間限制: 1 Sec  記憶體限制: 128 MB 提交: 22  解決: 19 [提交] [狀態] [討論版] [命題人:admin]

題目描述

用兩臺處理機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

思路:二進位制列舉每一種情況然後找最小的就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e3+10;
int work_A[maxn],work_B[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 0;i < n;i++)
	scanf("%d",&work_A[i]);
	for(int i = 0;i < n;i++)
	scanf("%d",&work_B[i]);
	int temp = (1 << n);
	int ans = 10000000;
	int sumA,sumB;
	for(int i = 0;i <= temp;i++)
	{
		sumA = 0;sumB = 0;
		int number = i;
		for(int j = 0;j < n;j++)
		{
			if(number & 1)
			sumA += work_A[j];
			else
			sumB += work_B[j];
			number /= 2;
		}
		//cout<<sumA<<" "<<sumB<<endl;
		ans = min(ans,max(sumA,sumB));
	}
	printf("%d\n",ans);
	return 0;
}