贪心两题(活动安排问题+删除最少字符得到目标字符)

看了一下算导中的贪心部分,然后总结一下贪心。

首先是算导上的简单活动安排问题(带权活动安排还没看),对于如果只是安排一个教室的话,为了让资源尽可能地被利用,我们选择把结束时间早的先放在前面,即按结束时间对活动进行排序。

然后遇到51nod的一道类似的题。不过不同的地方是它要求所有活动都必须安排完,上一个问题只要找到最大的不冲突子集就可以了。所以不能单纯的生搬硬套。最佳的策略是对于所有活动按开始时间排序,在开始时间相同的情况下,活动时间短的在前面。

编程时的思路:先对所有活动排序,然后每次贪心得出可以在一个教室进行活动的所有活动,对于有冲突而不能在同一个教室的,用另一个vector先存起来。然后循环贪心有冲突的活动,给他们分配教室。到所有活动分配完后结束。

51nod 1428代码:

#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
int n,si,ei,cnt;

struct party{
    int st,ed;
    party(int ss,int ee):st(ss),ed(ee){}
};

/*struct cmp{
    bool operator()(party a,party b){
        if(a.st==b.st)
            return a.ed>b.ed;
    return a.st>b.st;}
};*/

bool cmp(party a,party b){
    if(a.st==b.st)
        return a.ed<b.ed;
    return a.st<b.st;
}

void solve(vector<party> &v1){
        vector<party> v;
        party now=v1[0];
        //q1.pop();
        if(v1.size()==1)
        {v1.erase(v1.begin());return;}
        for(int i=1;i<v1.size();i++){
            party next=v1[i];
            if(next.st>=now.ed)
                now=next;
            else
                {v.push_back(next);/*cout<<next.st<<endl;*/}
        }
        v1.clear();
        for(int i=0;i<v.size();i++){
            v1.push_back(v[i]);
        }
        /*while(!q2.empty()){
            party p=q2.front();
            q2.pop();
            q1.push(p);
        }*/
}

int main(){
    while(scanf("%d",&n)!=EOF){
        //priority_queue<party,vector<party>,cmp> q1;
        vector<party> v1;
        cnt=0;
        for(int i=0;i<n;i++){
            scanf("%d%d",&si,&ei);
            v1.push_back(party(si,ei));
        }
        sort(v1.begin(),v1.end(),cmp);
        while(v1.size()){
        solve(v1);
        cnt++;
        }
        printf("%d\n",cnt);
    }
    return 0;
}

贪心之二:给出一串字符串,问如何可以删除最少的字符得出目标字符串。

思路:首先输入时记录目标字符串中的字符位置。解决时找到模板字符串中每个出现目标字符串首字母的位置开始往后搜索位置比当前大的且在目标字符串之后的字符,同时计算删除的字符个数。正确性也可以用剪切粘贴方法验证。

比赛时思路是很快想出来了,但是一直debug不出问题在哪,原因在于习惯于做标志判断是否退出,但是一个出发点不满足并不意味着就失败。所以以后遇到多起点判断是否存在可行解的时候最好不要通过标志位,只要判断一下输出的值的大小是否和刚开始初始化的值相等就可以了。

wa代码:

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<vector>
#include<iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+50;
char s[maxn];
bool judge;
int cc;
int main(){
    while(scanf("%s",s)!=EOF){
    vector<int> z,c,m,u;
    cc=inf;
    judge=true;
    int length=strlen(s);
    for(int i=0;i<length;i++){
        if(s[i]=='z')
            z.push_back(i);
        else if(s[i]=='c')
            c.push_back(i);
        else if(s[i]=='m')
            m.push_back(i);
        else if(s[i]=='u')
            u.push_back(i);
    }
    if(z.size()!=0){
    for(int i=0;i<z.size();i++){
        int cnt=0;
        int temp1=lower_bound(c.begin(),c.end(),z[i])-c.begin();
        if(temp1==c.size()){judge=false;continue;}
        //cout<<"c:"<<c[temp1]<<endl;
        cnt+=c[temp1]-z[i]-1;
        int temp2=lower_bound(m.begin(),m.end(),c[temp1])-m.begin();
        if(temp2==m.size()){judge=false;continue;}///设置judge=false,如果前面有可行解,后面某一个出发点无可行解,结果就会输出-1
        //cout<<"m:"<<m[temp2]<<endl;
        cnt+=m[temp2]-c[temp1]-1;
        int temp3=lower_bound(u.begin(),u.end(),m[temp2])-u.begin();
        if(temp3==u.size()){judge=false;continue;}
        //cout<<"u:"<<u[temp3]<<endl;
        cnt+=u[temp3]-m[temp2]-1;
        cc=min(cc,cnt);
    }
    }
    else
        judge=false;
    if(!judge)
        cc=-1;
    printf("%d\n",cc);
    }
    return 0;
}

AC代码:

#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<vector>
#include<iostream>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+50;
char s[maxn];
bool judge;
int cc;
int main(){
    while(scanf("%s",s)!=EOF){
    vector<int> z,c,m,u;
    cc=inf;
    judge=true;
    int length=strlen(s);
    for(int i=0;i<length;i++){
        if(s[i]=='z')
            z.push_back(i);
        else if(s[i]=='c')
            c.push_back(i);
        else if(s[i]=='m')
            m.push_back(i);
        else if(s[i]=='u')
            u.push_back(i);
    }
    if(z.size()!=0){
    for(int i=0;i<z.size();i++){
        int cnt=0;
        int temp1=lower_bound(c.begin(),c.end(),z[i])-c.begin();
        if(temp1==c.size()) continue;
        //cout<<"c:"<<c[temp1]<<endl;
        cnt+=c[temp1]-z[i]-1;
        int temp2=lower_bound(m.begin(),m.end(),c[temp1])-m.begin();
        if(temp2==m.size()) continue;
        //cout<<"m:"<<m[temp2]<<endl;
        cnt+=m[temp2]-c[temp1]-1;
        int temp3=lower_bound(u.begin(),u.end(),m[temp2])-u.begin();
        if(temp3==u.size()) continue;
        //cout<<"u:"<<u[temp3]<<endl;
        cnt+=u[temp3]-m[temp2]-1;
        cc=min(cc,cnt);
    }
    }
    /*else
        judge=false;*/
    if(cc==inf)
        cc=-1;
    printf("%d\n",cc);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值