10.21T8 rand()随机化/背包
Description
N(1 <= N <= 20)个干草堆,每堆的体积大小为Si(1 <= Si <= 100),需要分装到三个谷仓里。要求这三谷仓分得尽量平均(每堆草不可分割),即最大的一堆最小。请求出这最大的一个谷仓分得的体积。
Input
第一行: 整数 N.
第 2..1+N行:每行一个整数表示第第i堆的体积Si.
第 2..1+N行:每行一个整数表示第第i堆的体积Si.
Output
第1行:最大谷仓分得的干草堆体积和
Sample Input
8
14
2
5
15
8
9
20
4
Sample Output
26
此题使用堆然后直接看人品随机化就可以了
23333333
使用我的生日20020731做种子就AC了哈哈哈哈哈哈
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<ctime> 5 #include<cstdlib> 6 using namespace std; 7 priority_queue<int,vector<int>,greater<int> >q; 8 int a[30]; 9 int main() { 10 srand(20020731); 11 int n; 12 cin>>n; 13 for(int i=1; i<=n; i++) { 14 cin>>a[i]; 15 q.push(a[i]); 16 } 17 int min0=0x3f3f3f3f; 18 for(int o=1; o<=1200000; o++) { 19 int b[3]= {0,0,0},max0=0; 20 for(int i=1; i<=n; i++) { 21 int now=q.top(); 22 q.pop(); 23 b[(rand())%3]+=now; 24 } 25 max0=max(b[0],max(b[1],b[2])); 26 min0=min(min0,max0); 27 for(int i=1; i<=n; i++) { 28 q.push(a[i]); 29 } 30 } 31 cout<<min0; 32 return 0; 33 }
当然我们除此之外还有背包算法
令f[i][j]表示第一个谷仓体积为i,第二个为j是否存在,于是我们就可以直接暴力跑背包
当然因为转移的时候好像为了避免滚动数组的思考难度就用了两个数组复用
code:
1 #include <iostream> 2 using namespace std; 3 const int MAXS = 700; 4 5 int n, bale, tsum; 6 bool good[2][MAXS+100][MAXS+100]; 7 8 int main() 9 { 10 for (int i = 0; i < 2; i++) 11 for (int j = 0; j < MAXS; j++) 12 for (int k = 0; k < MAXS; k++) 13 good[i][j][k] = false; 14 good[0][0][0] = true; 15 tsum = 0; 16 17 fin >> n; 18 for (int i = 0; i < n; i++) 19 { 20 fin >> bale; 21 tsum += bale; 22 for (int j = 0; j < MAXS; j++) 23 for (int k = 0; k < MAXS; k++) 24 { 25 if (good[i%2][j][k]) 26 { 27 good[(i+1)%2][j][k] = true; 28 good[(i+1)%2][j+bale][k] = true; 29 good[(i+1)%2][j][k+bale] = true; 30 } 31 } 32 } 33 34 int ans = MAXS; 35 for (int i = 0; i < MAXS; i++) 36 for (int j = 0; j < MAXS; j++) 37 if (good[n%2][i][j]) 38 ans = min (ans, max (i, max (j, tsum - (i + j)))); 39 fout << ans <<"\n"; 40 return 0; 41 }
爆搜也是可以的
code:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 int a[25],n,ans=0x7fffffff; 5 void dfs(int k,int x,int y,int z){ 6 if(k==n+1){ans=min(ans,max(max(x,y),z));return ;} 7 //可行性减枝 8 if(ans-a[k]>x)dfs(k+1,x+a[k],y,z); 9 if(ans-a[k]>y&&x!=y)dfs(k+1,x,y+a[k],z); 10 if(ans-a[k]>z&&x!=z&&y!=z)dfs(k+1,x,y,z+a[k]); 11 } 12 int main(){ 13 scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]); 14 dfs(1,0,0,0);printf("%d",ans); 15 return 0; 16 }
神仙做法:排完序之后可以交换
code:
1 #include<iostream> 2 #include<iomanip> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 int n; 9 int s[200]={0}; 10 int minv[3]; 11 int ob[3][200]={0}; 12 int cnt[3]={0}; 13 bool cmp(int a,int b){return a>b;} 14 int get_maxpos(){int maxpos,vmax=0;for(int k=0;k<=2;k++)if(minv[k]>vmax){maxpos=k;vmax=minv[k];}return maxpos;} 15 int get_minpos(){int minpos,vmin=0x7fffffff;for(int k=0;k<=2;k++)if(minv[k]<vmin){minpos=k;vmin=minv[k];}return minpos;} 16 void tiaozheng(int a,int b){//通过枚举交换a,b的物品,使最大值最小 17 bool mark=0; 18 for(int i=1;i<=cnt[a];i++){ 19 for(int j=1;j<=cnt[b];j++){ 20 if(max(minv[a]-ob[a][i]+ob[b][j],minv[b]-ob[b][j]+ob[a][i])<max(minv[a],minv[b])){//如果交换后最大值最小 21 minv[a]=minv[a]-ob[a][i]+ob[b][j]; 22 minv[b]=minv[b]-ob[b][j]+ob[a][i]; 23 swap(ob[a][i],ob[b][j]);//交换两个物品 24 mark=1;//标记交换过 25 } 26 } 27 } 28 if(!mark)return;//如果之前有交换,继续交换最大和最小 29 int maxpos=get_maxpos(),minpos=get_minpos(); 30 if(minpos!=maxpos)tiaozheng(minpos,maxpos); 31 } 32 int main(){ 33 scanf("%d",&n); 34 for(int i=1;i<=n;i++)scanf("%d",&s[i]); 35 36 sort(s+1,s+n+1,cmp);//按从大到小排序 37 38 minv[0]=s[1];//初始赋值 39 ob[0][1]=s[1]; 40 cnt[0]=1; 41 //每步都保证当前最优 42 for(int i=2;i<=n;i++){ 43 int maxpos,minpos=get_minpos();//得到当前最小位置,加入s[i] 44 minv[minpos]+=s[i]; 45 cnt[minpos]++; 46 ob[minpos][cnt[minpos]]=s[i]; 47 maxpos=get_maxpos();minpos=get_minpos(); 48 if(minpos!=maxpos)tiaozheng(minpos,maxpos);//先交换最大的和最小的 49 tiaozheng(0,1);//尝试交换既不是最大也不是最小的 50 tiaozheng(2,1); 51 tiaozheng(0,2); 52 } 53 int ans=0; 54 ans=max(minv[0],minv[1]); 55 ans=max(ans,minv[2]); 56 cout<<ans; 57 return 0; 58 }
over 哈哈哈哈哈哈哈哈哈哈哈哈嗝