1. 程式人生 > >貪心 區間相關(貪心策略+注意細節) 一定一定要學會造樣例啊

貪心 區間相關(貪心策略+注意細節) 一定一定要學會造樣例啊

1、區間選擇最少的點覆蓋

寫那種找滿足條件的數的時候還是用while迴圈更加優雅一些啊,我寫的for跟狗屎一樣,主要還是一開始貪心的姿勢錯了

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int r,n;
const int N=1e3+10;
int loc[N];
int vis[N];
int main()
{
    while(cin>>r>>n)
    {

        if(r==-1&&n==-1) break;
        for(int i=1;i<=n;++i)
            cin>>loc[i];
        sort(loc+1,loc+1+n);
        int ans=0,i=1;
        while(i<=n)
        {
            int left=loc[i++];
            while(i<=n&&left+r>=loc[i]) ++i;
            left=loc[i-1];//
            while(i<=n&&left+r>=loc[i]) ++i;
            ++ans;
        }
        cout<<ans<<endl;

    }
        /*int last=1;
        int ans=0;

        for(int i=1;i<=n;++i)
        {
           if(loc[i]-loc[last]>r)  //從last開始計算距離 已經超了 ,<r就繼續向左走
            {
                //i-1是<=r範圍內的最後一個
                if(i-1==last&&i==2){++ans;last=2;vis[1]=1; continue;}
                if(i-1==last&&loc[last]-loc[last-1]<=r)//向右沒找到並且向左也沒有能覆蓋的
                {
                    last=i;
                    continue;
                }
                else
                {
                    vis[i-1]=1;
                    last=i;
                    ++ans;
                }

            }
        }
        ++ans;   //把包含最後一個位置的組給加進去
        cout<<ans<<endl;
    }*/   //還是思維錯了

    return 0;
}

2、區間選點問題

poj 1328 Radar Installation 如果雷達點只能是整數的話,也不能退化成上面一種情況,一開始貪心策略錯了,大白上這個區間的模板真好用啊。

#include<iostream>
#include<algorithm>
#include<math.h>
#include<stdio.h>
using namespace std;
int n;
double d;
typedef struct dot
{
    int x,y;
};
struct interval
{
    double s,t;
};
bool cmp(interval a,interval b)
{
    if(a.t==b.t)
        return a.s>b.s;
    else return a.t<b.t;
}
dot pnt[1010];
interval inter[1010];
int main()
{
    int kase=0;
    while(cin>>n>>d)
    {
        if(!n&&!d) break;
        int maxx=0;
        for(int i=1;i<=n;++i)
        {
            cin>>pnt[i].x>>pnt[i].y;
            maxx=max(pnt[i].y,maxx);
            inter[i].s=pnt[i].x-sqrt(d*d-pnt[i].y*pnt[i].y);
            inter[i].t=pnt[i].x+sqrt(d*d-pnt[i].y*pnt[i].y);
        }
        ++kase;
        if(maxx>d) {printf("Case %d: -1\n",kase); continue;}
        sort(inter+1,inter+1+n,cmp);
        int ans=0;
        int i=1;
        while(i<=n)
        {
            double last=inter[i++].t;
            while(i<=n&&inter[i].s<=last) ++i;  //==也是
            ++ans;
            last=inter[i].t;
        }
        printf("Case %d: %d\n",kase,ans);

    }
    return 0;
}
//感覺和poj 3069有點像 那我就延續這個思路好了
//真的智熄,誰告訴我d是整數了,又是誰告訴我座標只能在整數的地方啊啊啊啊啊啊
//#include<iostream>
//#include<algorithm>
//#include<stdio.h>
//using namespace std;
//typedef long long LL;
//int n;
//LL d;
//typedef struct dot
//{
//    LL x,y;
//};
//dot pnt[1010];
//bool cmp(dot a,dot b)  //優先排x
//{
//    if(a.x==b.x) return a.y>b.y;  //大y優先
//    else return a.x<b.x;
//}
//int main()
//{
//    LL kase=0;
//    while(cin>>n>>d)
//    {
//        if(n==0&&d==0) break;
//        ++kase;
//        LL maxx=0;
//        for(int i=1;i<=n;++i)
//        {
//             cin>>pnt[i].x>>pnt[i].y;
//             maxx=max(maxx,pnt[i].y);
//        }
//        if(maxx>d) {printf("Case %lld: -1\n",kase); continue;}
//        sort(pnt+1,pnt+1+n,cmp);
//        int i=1;
//        LL ans=0;
//        while(i<=n)
//        {
//            LL left=pnt[i].x;
//            while(i<=n&&(LL)((pnt[i].x-left)*(pnt[i].x-left)+pnt[i].y*pnt[i].y)<=d*d) ++i;
//            left=pnt[i-1].x;   //此時就顯示了大y優先的優越性啦
//            while(i<=n&&(LL)((pnt[i].x-left)*(pnt[i].x-left)+pnt[i].y*pnt[i].y)<=d*d) ++i;
//            ++ans;
//        }
//        printf("Case %lld: %lld\n",kase,ans);
//    }
//    return 0;
//}

3、區間覆蓋問題(一定一定要學會造樣例,最好寫前把虛擬碼寫好,把每一步可能出現的情況想好)

wa點有兩個,其中之一是每次從上一個結束的下一個開始就好了,這個屬於讀題是否細心的問題

wa點之二由hzoi_battleship提供, 6 5

1 4

1 5

4 5

1 1

2 2

3 4 ,我一開始的程式碼會輸出-1,因為第一個被選的是1,5,之後while迴圈會把i加到7,把我的maxx給修改為0了

這個是思維上的錯誤,主要是i<=n這個限制條件沒攔住,且程式碼影響了我全域性的引數,還是思維的嚴謹性叭

// 區間覆蓋問題 選擇儘量少的區間覆蓋1-T
//wa點之一每次從上一個結束的下一個開始就好了
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=25000+10;
struct cow
{
    int s,t;
};
cow c[N];
int n,T;
bool cmp(cow a,cow b)
{
    if(a.s==b.s)
        return a.t>b.t;   //這樣被包含的區間就會跳過了
    else return a.s<b.s;
}

int main()
{
    scanf("%d%d",&n,&T);
    for(int i=1;i<=n;++i)
        scanf("%d%d",&c[i].s,&c[i].t);
    sort(c+1,c+1+n,cmp);
    if(c[1].s>1) {printf("-1\n");return 0;}
   // if(c[n].t<T) {printf("-1\n");return 0;}
    int i=1,ans=1;
    int flag=1; //控制中間能接上
    int last=c[1].t;
    int maxx;  //能夠記錄最後一次覆蓋到哪
    while(i<=n)
    {
        maxx=c[i].t;
        //if(last>=T) break;  //6 5 1 4 1 5 4 5 1 1 2 2 3 4 這裡不break的話,i會迴圈到7,導致maxx變為0,-1退出
        //也就是說我在後面的判斷中沒有控制好i的範圍,導致關鍵引數被修改
        while(i<=n&&c[i].t<=last) ++i;  //被包含的直接跳過
//        cout<<i<<endl;
        if(c[i].s-last>1) {flag=0;break;} //沒有接上
        else if(i<=n)
        {

            maxx=c[i].t;
            while(i<=n&&c[i].s-last<=1)
            {
                maxx=max(maxx,c[i].t);
               // cout<<i<<":"<<maxx<<endl;
                ++i;
            }
            ++ans;
            last=maxx;
        }
    }

    if(maxx<T) printf("-1\n");
    else if(!flag) printf("-1\n");
    else printf("%d\n",ans);
    return 0;
}

    //中間的貪心選擇錯了,不應該找t>last的,這樣可能不是最優解 要在符合條件的範圍內選擇結束最晚的
//    while(i<=n)
//    {
//        int last=c[i].t;
//        while(i<=n&&c[i].t<=last) ++i;
//        if(c[i].s-last>1)
//        {
//            flag=0;
//            break;
//        }
//        else
//        {
//            last=c[i].t;
//            ++ans;
//        }
//    }
//    if(!flag) printf("-1\n");
//    else printf("%d\n",ans);

4、區間不相交

一開始就想往區間不相交上去靠,靠出來的結果x,n-x是需要的stall數,但是這個過程中不好儲存哪個牛對應哪個stall

本題複習了優先權佇列,一直覺得優先權佇列自定義優先順序很amazing,sort裡 return <是按照升序排列,

bool operator <中return >是越小的越在前面

#include<iostream>
#include<queue>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int maxn=5e4+10;
struct cow  //怎麼由結束時間t反向追蹤到欄號呢,emmm ,傻了啊優先權佇列裡面直接存cow
{
    int s,t;
    int id; //按照開始時間排序後要按照原來的順序輸出,忘記這一點了
    int stall;
    friend bool operator <(cow a,cow b)
    {
        return a.t>b.t;       //結束時間早的優先順序高
    }
   //通過自定義operator<操作符來比較元素中的優先順序。
    //在過載”<”時,最好不要過載”>”,可能會發生編譯錯誤

};
cow c[maxn];
int n;
priority_queue<cow> pq;
bool cmp1(cow a,cow b)
{
    if(a.s==b.s) return a.t<b.t;
    else return a.s<b.s;
}
bool cmp2(cow a,cow b)
{
    return a.id<b.id;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&c[i].s,&c[i].t);
        c[i].id=i;
    }
    sort(c+1,c+1+n,cmp1);
    int cnt=0;
    ++cnt;
    c[1].stall=cnt;  //差點弄錯順序,先把stall存進去才行
    pq.push(c[1]);

    for(int i=2;i<=n;++i)
    {
        if(!pq.empty())
        {
            cow tmp=pq.top();
            if(tmp.t>=c[i].s)
             {
                 ++cnt;
                 c[i].stall=cnt;
                 pq.push(c[i]);

             }
             else
             {
                 c[i].stall=tmp.stall;
                 pq.pop();
                 pq.push(c[i]);
             }
        }

    }
    printf("%d\n",cnt);
    sort(c+1,c+1+n,cmp2);
    for(int i=1;i<=n;++i)
        printf("%d\n",c[i].stall);

    return 0;
}

還有一個wa點經常會踩到,就是排序後打亂了順序,輸出的時候順序不對