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

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4/4 贪心选数+最长上升子序列+简单染色二分图+二进制搜索相关的知识,希望对你有一定的参考价值。

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;


以上是关于4/4 贪心选数+最长上升子序列+简单染色二分图+二进制搜索的主要内容,如果未能解决你的问题,请参考以下文章

LIS 最长上升子序列问题(动态规划贪心+二分)

LIS 最长上升子序列问题(动态规划贪心+二分)

贪心+二分查找:最长上升子序列(3.14 leetcode每日打卡)

AcWing 895 最长上升子序列 - (线性DP) or (贪心+二分优化)

精读《DOM diff 最长上升子序列》

线性状态动态规划 P1020 导弹拦截最长上升子序列