zl程序教程

您现在的位置是:首页 >  其他

当前栏目

4/4 贪心选数+最长上升子序列+简单染色二分图+二进制搜索

搜索序列二进制 简单 二分 最长 贪心 上升
2023-09-11 14:15:53 时间

P6268 [SHOI2002]舞会
先染色区分男女生。再套二分匹配的板子,求出最小路径覆盖。

#include <bits/stdc++.h>

using namespace std;
const int maxn=1005;
int n,m,g[maxn][maxn],link[maxn],col[maxn];
bool used[maxn];
void cc(int u,int pre,int color)
{
    col[u]=color;
    for(int i=1;i<=n;i++)
    {
        if(g[u][i]&&!col[i])
            cc(i,u,3-color);
    }
    return;
}
int dfs(int u)
{
    for(int i=1;i<=n;i++)
    {
        if(col[i]==1) continue;
        if(!used[i]&&g[u][i])
        {
            used[i]=1;
            if(link[i]==-1||dfs(link[i]))
            {
                link[i]=u;return 1;
            }
        }
    }
    return 0;
}
int hungary()
{
    int res=0;
    memset(link,-1,sizeof(link));
    for(int i=1;i<=n;i++)
    {
        if(col[i]==2) continue;
        memset(used,0,sizeof(used));
        if(dfs(i))
            res++;
    }
    return res;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int u,v;cin>>u>>v;
        u++;v++;
        g[u][v]=g[v][u]=1;
    }
    for(int i=1;i<=n;i++) //区分男女生
    {
        if(!col[i]) cc(i,0,1);
    }
    cout<<n-hungary()<<endl;
    return 0;
}

# C. Magical Rearrangement
一个较难的贪心细节题。
分为两大类:
如果0的数目不是最多时,无解的情况:1.mx>=rest+2
如果0的数目是最多的,无解的情况:2.mx>=rest+1
一组特判:rest==0,num[0]==1,此时输出一个0
put(int last)函数的作用:当前选的数字不能和last相同,满足相邻两位不同;
由于不能拥有前导0,因此从0开始。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int num[15];
int put(int last)
{
    for(int i=0;i<=9;i++)
    {
        if(num[i]==0||i==last)
            continue;
        num[i]--;
        int id=0,rest=0,mx=0;
        for(int j=0;j<=9;j++)
        {
            rest+=num[j];
            if(mx<num[j])
            {
                mx=num[j];id=j;
            }
        }
        rest-=mx;
        if((id==i&&mx>=rest+1)||(id!=i&&mx>=rest+2))
            num[i]++;
        else
            return i;
    }
    return -1;
}
signed main()
{
    int t;cin>>t;
    while(t--)
    {
        int rest=0,mx=0,id;
        for(int i=0;i<=9;i++)
        {
            cin>>num[i];
            rest+=num[i];
            if(mx<num[i])
            {
                mx=num[i],id=i;
            }
        }
        rest-=mx;
        if(rest==0&&num[0]==1)
        {
            cout<<0<<endl;continue;
        }
        if(id==0&&mx>=rest+1)
        {
            cout<<-1<<endl;continue;
        }
        else if(id!=0&&mx>=rest+2)
        {
            cout<<-1<<endl;continue;
        }
        int x=put(0);
        while(x>=0)
        {
            cout<<x;x=put(x);
        }
        cout<<endl;
    }
    return 0;
}

# P1091 [NOIP2004 提高组] 合唱队形
求出两个最长上升子序列,拼接长度减去重复记的自身(减去1即可)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int a[105],f[105],d[105];

signed main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i],f[i]=d[i]=1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
    {
        if(a[i]>a[j])
            f[i]=max(f[i],f[j]+1);
    }
    for(int i=n-1;i>=1;i--)
        for(int j=i+1;j<=n;j++)
        if(a[i]>a[j])
            d[i]=max(d[i],d[j]+1);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=max(ans,f[i]+d[i]-1);
    }
    cout<<n-ans<<endl;
    return 0;
}

P1461 [USACO2.1]海明码 Hamming Codes
一道二进制的搜索题。
1.两个数字异或能统计出有多少个1.
2.要保证序列最小,第一个数字肯定是0.

#include <bits/stdc++.h>

using namespace std;
const int maxn=1005;
int n,b,d,a[105],cnt;
int check(int x,int y)
{
    int g=x^y;
    int num=0;
    while(g)
    {
        if(g%2==1) num++;
        g/=2;
    }
    return num;
}
int main()
{
    cin>>n>>b>>d;
    a[++cnt]=0;
    int mx=1<<b;
    while(cnt<n)
    {
        for(int i=a[cnt]+1;i<mx;i++)
        {
            if(check(a[cnt],i)>=d)
            {
                int f=0;
                for(int j=1;j<=cnt-1;j++)
                {
                    if(check(a[j],i)<d)
                    {
                        f=1;break;
                    }
                }
                if(!f)
                {
                    a[++cnt]=i;
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout<<a[i]<<" ";
        if(i%10==0) cout<<endl;
    }
    return 0;
}