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;
}