貪心 區間相關(貪心策略+注意細節) 一定一定要學會造樣例啊
阿新 • • 發佈:2018-12-19
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點經常會踩到,就是排序後打亂了順序,輸出的時候順序不對