Codeforces lucky country dp+优化
将原图跑一遍dfs找出每个联通块的的数量a[i],于是就能得到一个很明显的dp方程
dp[i][j]=min(dp[i-1][j-a[i]])+1
但复杂度是O(n²),过不了
于是我们可以想到优化
很明显,当数据量很大的时候一定会有大量的重复数据,所以我们可以考虑b[x]=∑(a[i]==x),之后就可以用二进制分解来优化
#include<iostream> #include<algorithm> #include<cstdio> #include<string> #include<cstring> #include<cassert> #include<cmath> #include<sstream> #include<fstream> #include<map> #include<set> #include<vector> #include<queue> #include<stack> #include<bitset> using namespace std; int lucky[105],lcnt; void init() { queue<string> q; q.push("4");q.push("7"); while(!q.empty()) { string tmp=q.front(); q.pop(); stringstream ss; ss<<tmp; int x; ss>>x; lucky[lcnt++]=x; if(x>10005)continue; q.push(tmp+"4"); q.push(tmp+"7"); } } vector<int> nei[100005]; int gro; int siz[100005]; bool vis[100005]; void dfs(int v) { if(vis[v]) return; vis[v]=1; siz[gro]++; for(int i=0;i<nei[v].size();i++) { int u=nei[v][i]; dfs(u); } } int n,m; int dp[500005]; void solve(int x,int y) { for(int i=n;i>=x;i--) { if(dp[i-x]!=-1) { if(dp[i]!=-1)dp[i]=min(dp[i-x]+y,dp[i]); else dp[i]=dp[i-x]+y; } } } int main() { init(); cin>>n>>m; for(int i=0;i<m;i++) { int x,y; cin>>x>>y; x--,y--; nei[x].push_back(y); nei[y].push_back(x); } map<int,int> num; for(int i=0;i<n;i++) { if(!vis[i]) { dfs(i); num[siz[gro]]++; gro++; } } memset(dp,-1,sizeof dp); dp[0]=0; map<int,int>::iterator it=num.begin(); for(;it!=num.end();it++) { int x=it->first,y=it->second; for(int j=1;j<y;j<<=1) { solve(j*x,j); y-=j; } solve(y*x,y); } int mi=1e9; for(int i=0;i<lcnt;i++) { if(dp[lucky[i]]!=-1)mi=min(dp[lucky[i]],mi); } if(mi!=1e9)cout<<mi-1; else cout<<-1; return 0; }
还有一种优化的方法,可以使用完全背包问题的优化方法
1 #include <bits/stdc++.h> 2 #define INF 1000000009 3 using namespace std; 4 5 int n,m,dp[100010],num[100010]; 6 bool vis[100010]; 7 vector<int> v[100010],ans; 8 9 int dfs(int u) 10 { 11 int sum=0; 12 for(int i=0;i<v[u].size();i++) if(!vis[v[u][i]]){ 13 vis[v[u][i]]=true; 14 sum+=dfs(v[u][i])+1; 15 } 16 return sum; 17 } 18 19 bool lucky(int x) 20 { 21 if(x==0) return false; 22 bool flag=true; 23 while(x!=0){ 24 int y=x%10; 25 if(y!=4&&y!=7) flag=false; 26 x/=10; 27 } 28 return flag; 29 } 30 31 int main() 32 { 33 cin>>n>>m; 34 for(int i=1;i<=m;i++){ 35 int x,y; 36 cin>>x>>y; 37 v[x].push_back(y); 38 v[y].push_back(x); 39 } 40 for(int i=1;i<=n;i++) if(!vis[i]){ 41 vis[i]=true; 42 int nm=dfs(i)+1; 43 if(num[nm]==0) ans.push_back(-nm),num[nm]=1; 44 else num[nm]++; 45 } 46 sort(ans.begin(),ans.end()); 47 dp[0]=0; 48 for(int i=1;i<=n;i++) dp[i]=INF; 49 for(int i=0;i<ans.size();i++){ 50 map<int,int> mp; 51 for(int j=-ans[i];j<=n;j++){ 52 if(dp[j]>dp[j+ans[i]]+1&&mp[j+ans[i]]+1<=num[-ans[i]]){ 53 dp[j]=dp[j+ans[i]]+1; 54 mp[j]=mp[j+ans[i]]+1; 55 } 56 } 57 } 58 int ans=INF; 59 for(int i=0;i<=n;i++){ 60 if(lucky(i)) ans=min(ans,dp[i]); 61 } 62 if(ans==INF) ans=0; 63 cout<<ans-1<<endl; 64 return 0; 65 }

浙公网安备 33010602011771号