Codeforces 95E Lucky Country解题报告
点击这里进入题目
题意:有N个国家,每个国家之间一共有M条无向路。国家会由路连成一个个联通块,然后问你要最少添加几条边,使最大的联通块的点的个数为一个幸运数(只包含4或7的数)。
思路:首先要做的肯定是处理联通块,可以用dfs或并查集,把每个连通块的大小都记录下来,这时候假如把每一个作为一个单独的来处理会很慢,我们要做的是把相同大小的放在一起,记录相同大小联通块的数量,再整体dp。
AC程序
//库省略
using namespace std;
const int maxn=100005,inf=1e9+7;
int fa[maxn];
ll n,m,dp[maxn];
int sz[maxn],costs[maxn];
vector<int> fas;
bool vis[maxn];
int findfa(int x)
{
if(fa[x]==x)
return x;
else
return fa[x]=findfa(fa[x]);
}
void bag(int wei,int val)
{
for(int i=n;i>=wei;i--)
{
dp[i]=min(dp[i],dp[i-wei]+val);
}
}
bool check(int xx)
{
while(xx)
{
if((xx%10)!=4 && (xx%10)!=7)
{
return 0;
}
if(xx<10)
break;
xx/=10;
}
return 1;
}
int main()
{
memset(dp,1e9+7,sizeof(dp));
cin>>n>>m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
fa[findfa(x)]=findfa(y);
}
for(int i=1;i<=n;i++)
{
sz[findfa(i)]++;
}
for(int i=1;i<=n;i++)
{
costs[sz[i]]++;
}
//cout<<dp[0]<<endl;
dp[0]=0;
for(int i=1;i<=n;i++)
{
if(costs[i])
{
//cout<<i<<" "<<costs[i]<<endl;
for(int j=1;j<=costs[i];j<<=1)
{
bag(j*i,j);
costs[i]-=j;
}
bag(costs[i]*i,costs[i]);
}
}
ll ans=1e9+7;
for(int i=1;i<=n;i++)
{
//cout<<i<<" "<<dp[i]<<endl;
if(check(i))
ans=min(ans,dp[i]);
}
if(ans==1e9+7)
cout<<"-1"<<endl;
else
cout<<ans-1<<endl;
return 0;
}