1. 程式人生 > 其它 >SystemC事務級建模01之最簡單的模組間資料傳輸

SystemC事務級建模01之最簡單的模組間資料傳輸

01揹包
有一個容量為\(V\)的揹包和\(N\)種物品。知道每種物品的價值\(w_{i}\)和體積\(v_{i}\)(一種物品只有一個),求在揹包能裝下的情況下能拿走的物品的最大總價值。
思路:
\(f_{ij}\)表示前\(i\)種中能拿走的物品總體積為\(j\)時能拿走的物品的最大總價值。對於第\(i\)種物品,有選或不選兩種情況,選了,前\(i-1\)種物品中能拿走的物品總體積為\(j-v_{i}\)就是\(f_{ij}\)的前一個狀態,即\(f_{ij}=f_{i-1j-v_{i}}+w_{i}\),不選,就是從\(f_{i-1j}\)直接轉移過來,即\(f_{ij}=f_{i-1j}\)

,兩個式子合併後就是\(f_{ij}=max\left(f_{i-1j-v_{i}},f_{i-1j}\right)\)
程式碼:

#include<iostream>
using namespace std;
int N,V;
int v[110],w[110];
int f[110][1010];
int ans=0;
int main(){
	cin>>V>>N;
	for(int i=1;i<=N;i++){
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=N;i++){
		for(int j=0;j<=V;j++){
			if(j>=v[i])f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
			else f[i][j]=f[i-1][j];
			ans=max(ans,f[i][j]);
		}
	}
	cout<<ans;
	return 0;
} 

完全揹包
這個和01揹包只有一點不同,每種物品有無窮多個。
思路:
這裡每種物品可以不拿,拿一個,拿兩個,……只要揹包能裝下,即\(f_{ij}= \underset{0<=k<=j/v_{i}}{max} f_{i-1j-k*v_{i}}+k*w{i}\)
程式碼:

#include<iostream>
using namespace std;
int N,V;
int v[110],w[110];
int f[110][1010];
int ans=0;
int main(){
	cin>>N>>V;
	for(int i=1;i<=N;i++){
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=N;i++){
		for(int j=0;j<=V;j++){
			for(int k=0;k<=j/v[i];k++){	
				f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);
			}
			ans=max(ans,f[i][j]);
		}
	}
	cout<<ans;
	return 0;
} 

但是這樣的時間複雜度是\(O(n^{3})\),很慢,既然每件物品能拿無窮多個,也就是說無論什麼情況下(揹包不能裝了除外),可以拿任何一種物品,\(f_{j}\)表示用\(j\)的空間能拿走的物品價值總和最大值,即\(f_{j}=max(f_{j},f_{j-v_{i}}+w_{i})\)
程式碼:

#include<iostream>
using namespace std;
int N,V;
int v[1010],w[1010];
int f[1010];
int ans=0;
int main(){
	cin>>N>>V;
	for(int i=1;i<=N;i++){
		cin>>v[i]>>w[i];
	}
	for(int i=1;i<=N;i++){
		for(int j=0;j<=V;j++){
			if(j>=v[i])f[j]=max(f[j],f[j-v[i]]+w[i]);
		}
	}
	for(int j=0;j<=V;j++){
	    ans=max(ans,f[j]);
	}
	cout<<ans;
	return 0;
} 

多重揹包
也是隻與01揹包有一處不同,就是每種物品有\(s_{i}\)個。
思路:
只需要在完全揹包的\(O(n^{3})\)做法上加一個限制\(k<=s[i]\),即\(f_{ij}= \underset{0<=k<=min(j/v_{i},s[i])}{max} f_{i-1j-k*v_{i}}+k*w{i}\)
程式碼

#include<iostream>
using namespace std;
int n,v;
int u[110],w[110],s[110];
int f[110][110];
int ans=0;
int main(){
    cin>>n>>v;
    for(int i=1;i<=n;i++){
        cin>>u[i]>>w[i]>>s[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=v;j>=0;j--){
            for(int k=0;k<=min(s[i],j/u[i]);k++){
                f[i][j]=max(f[i][j],f[i-1][j-k*u[i]]+k*w[i]);
            }
            ans=max(ans,f[i][j]);
        }
    }
    cout<<ans;
    return 0;
}

但是\(O(n^{3})\)還是慢,這裡可以用二進位制優化,是將每種物品進行分組,第一組1個,第二組2個,第三組4個,以此類推,直到不滿一組,則剩下的全部歸為一組。
這樣可以組合成所有情況,從第一組開始,可以滿足\([0,1]\)中的所有情況,第二組滿足\([2,3]\)中的所有情況,加上前面就是可以滿足\([0,3]\)中所有情況,以此類推,到最後一組就可以滿足\([0,s_{i}]\)中的所有情況。每組只有一個,這就是01揹包問題。
程式碼:

#include<iostream>
using namespace std;
int n,v;
int u[1010],w[1010],s[1010];
int wet[12010],val[12010],t[12010];
int f[2010];
int cnt=0;
int main(){
	cin>>n>>v;
	for(int i=1;i<=n;i++){
		cin>>u[i]>>w[i]>>s[i]; 
	}
	for(int i=1;i<=n;i++){
		int k=1;
		while(k<s[i]){
			t[++cnt]=k;
			s[i]-=k;
			wet[cnt]=t[cnt]*u[i];
			val[cnt]=t[cnt]*w[i];
			k*=2;
		}
		t[++cnt]=s[i];
		wet[cnt]=t[cnt]*u[i];
		val[cnt]=t[cnt]*w[i];
	}
	for(int i=1;i<=cnt;i++){
		for(int j=v;j>=0;j--){
			if(j>=wet[i])f[j]=max(f[j],f[j-wet[i]]+val[i]);
		}
	}
	int ans=0;
	for(int i=0;i<=v;i++){
		ans=max(ans,f[i]);
	}
	cout<<ans;
	return 0;
}

分組揹包
就是在01揹包的基礎上,將物品進行了分組,且規定一組中只能選擇一件物品。
思路:
也是在01揹包上進行輕微改動,\(f_{ij}\)中的\(i\)表示前\(i\)組,其餘照01揹包做就可以了。
程式碼:

#include<iostream>
using namespace std;
int n,v;
int mo[110],cnt;
int u[10010],w[10010];
int f[110][110];
int ans=0;
int main(){
    cin>>n>>v;
    cnt=1;
    for(int i=1;i<=n;i++){
        cin>>mo[i];
        mo[i]=mo[i-1]+mo[i];
        for(;cnt<=mo[i];cnt++){
            cin>>u[cnt]>>w[cnt];
        }
    }
    cnt=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=v;j++){
            f[i][j]=f[i-1][j];
        }
        for(;cnt<=mo[i];cnt++){
            for(int j=0;j<=v;j++){
                if(j>=u[cnt])f[i][j]=max(f[i][j],f[i-1][j-u[cnt]]+w[cnt]);
            }
        }
        for(int j=0;j<=v;j++){
            ans=max(ans,f[i][j]);
        }
    }
    cout<<ans;
    return 0;
}