題目鏈接
題意的話給出了n個01串,1代表該位置是亮的,我們必須把m個位置變亮後且都是數字。求能組成的最大數字。每個位置代表的地方看題目給的圖吧。
思路
明顯的dp題,我們假設表示前個數字花費次機會後能形成具體數字。那麼其狀態轉移方程爲:注意這裏的表示的是第個數字變成所需的機會。那麼當時也就是這個數字可以形成具體數字,而最大數字直接可以貪心得到,具體參考代碼。
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
#include<map>
using namespace std;
const int N = 2e3+5;
typedef long long ll;
#define rep(i,a,b) for(i=(a);i<=b;i++)
#define pt(a) printf("%d\n",(a))
char a[N][N],b[10][10]={ "1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011"};
int q[N][10];
bool solve(int x){
bool flag = false;
for(int i=0;i<10;i++){
int sum=0;
int j;
for(j=0;j<7;j++){
if(a[x][j]==b[i][j]) continue;
else if(b[i][j]=='0') break;
else sum++;
}
if(j==7) flag=true,q[x][i]=sum;
else q[x][i]=-1;
}
return flag;
}
int ans[N],dp[N][N];
bool dfs(int x,int y){
if(dp[x][y]!=-1) return dp[x][y];//記憶化爆搜,其中-1爲未達點,0爲失敗點,1爲成功點
for(int i=9;i>=0;i--){
if(q[x][i]!=-1){
ans[x]=i;
//printf("%d %d\n",x,i);
if(y<q[x][i]) continue;
if(dfs(x+1,y-q[x][i])){
dp[x][y]=1;
return true;
}
}
}
dp[x][y]=0;
return false;
}
int main()
{
int n,m,i,j,k,t=0,tot=0;
scanf("%d %d",&n,&m);
for(i=1;i<=n+2;i++) for(j=0;j<=m+2;j++) dp[i][j]=-1;
for(i=1;i<=n;i++)scanf("%s",a+i);
for(i=1;i<=n;i++){
if(!solve(i)){
printf("-1\n");
return 0;
}
}
dp[n+1][0]=1;
if(dfs(1,m)){
rep(i,1,n){
printf("%d",ans[i]);
}
printf("\n");
}
else{
printf("-1\n");
}
//system("pause");
return 0;
}
總結
這題莫名其妙被我看成了分組揹包,(太久沒刷題,把揹包定義都忘了分組揹包,在同一個組裏面最多取一個),而這一題必須取一個,所以wa是很正常的!當然如果有朋友發現可以寫的話,可以留言讓我修改喲。