假期訓練六(poj-1753,遞迴+hdu-2844,多重揹包)
阿新 • • 發佈:2019-01-12
題目一:傳送門
題意:有一個4*4的棋盤,每次翻轉一個棋子和它的上下左右的四個棋子,判斷翻轉多少次之後可以變為純色的棋盤。
思路:總共有C(0,16)+C(1,16)+C(2,16)+……+C(16,16)=2^16次,所以最多有16個棋子被翻動,然後從(0,0)個棋子開始,依次翻轉其他棋子,
判斷最少要翻轉多少個棋子,記著要回溯。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int INF = 99999999; charView Codestr[10][10]; int a[10][10],mi,zz[5][2]={0,0, 0,1, 0,-1, 1,0, -1,0}; void turn(int x,int y) { for(int i=0;i<5;i++) { int x1=x+zz[i][0]; int y1=y+zz[i][1]; if(x1>=0&&x1<4&&y1>=0&&y1<4) { a[x1][y1]=!a[x1][y1]; } } }bool pd() { for(int i=0;i<4;i++) { for(int j=0;j<4;j++) if(a[0][0]!=a[i][j]) return false; } return true; } void dfs(int x,int y,int num) { if(pd()) { mi=mi>num?num:mi; return ; } if(x==4) return ; turn(x,y); if(y==3) dfs(x+1,0,num+1); else dfs(x,y+1,num+1); turn(x,y); if(y==3) dfs(x+1,0,num); else dfs(x,y+1,num); } int main(void) { int i,j,n,m; for(i=0;i<4;i++) scanf("%s",str[i]); for(i=0;i<4;i++) { for(j=0;j<4;j++) a[i][j]=str[i][j]=='b'?0:1; } mi=INF; dfs(0,0,0); if(mi<=16) printf("%d\n",mi); else printf("Impossible\n"); return 0; }
題目二:傳送門
題意:有n個種硬幣,最大不超過m,給出每種硬幣的價值和數量,求不超過m的情況下能組成多少種價格。
思路:多重揹包;
(注意:當時因為審題不清,沒理解多少種價格的意思,其實就是dp[i]==i的情況)。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 100100; int val[maxn],num[maxn],dp[maxn],a[maxn*2]; int MAX(int x,int y) { return x>y?x:y; } int main(void) { int n,m,i,j,pt,cnt; while(scanf("%d%d",&n,&m)&&(n+m)) { memset(dp,0,sizeof(dp)); memset(a,0,sizeof(a)); for(i=1;i<=n;i++) scanf("%d",&val[i]); for(pt=1,i=1;i<=n;i++) { scanf("%d",&cnt); for(j=1;j<=cnt;j*=2) { a[pt++]=j*val[i]; cnt-=j; } if(cnt>0) a[pt++]=cnt*val[i]; } for(i=1;i<pt;i++) { for(j=m;j>=a[i];j--) dp[j]=MAX(dp[j],dp[j-a[i]]+a[i]); } int ans=0; for(i=1;i<=m;i++) if(i==dp[i]) ans++; printf("%d\n",ans); } return 0; }View Code