【POJ3614】【USACO 2007 Nov Gold】 3.Sunscreen 貪心
阿新 • • 發佈:2019-01-05
題意:
有若干個區間,若干種數,每個數告訴你有多少個。
然後一個數可以被放到一個x∈該區間 的區間,問最多有多少個區間可以被放。
題解:
顯然我們可以用二分圖最大匹配做,水題。
但是此題有別的技巧、
就是我們可以貪心進行處理。
首先我們考慮到需要將兩種數都排個序。
然後再進行貪心。
一種錯誤的貪心法是單調佇列式貪心,就是記錄個top,然後單調往後推。
這個不仔細想還不知道它是錯的。
額,至於卡它的資料,,我可以提供給你一個錯誤程式碼和一個拍子,你們可以自己拍一組資料出來,很高效。
這裡貼一份錯誤程式碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 3000 #define inf 0x3f3f3f3f using namespace std; int n,m,ans,i; struct KSD { int x,y; bool operator < (const KSD &a)const{return x==a.x?(y<a.y):(x<a.x);} }cow[N],oil[N]; int main() { // freopen("test.in","r",stdin); scanf("%d%d,",&n,&m); for(i=1;i<=n;i++)scanf("%d%d",&cow[i].x,&cow[i].y); for(i=1;i<=m;i++)scanf("%d%d",&oil[i].x,&oil[i].y); sort(cow+1,cow+n+1); sort(oil+1,oil+m+1); int top=1; for(i=1;i<=m;i++) { while(top<=n&&cow[top].y<oil[i].x)top++; while(top<=n&&oil[i].y&&cow[top].x<=oil[i].x) { if(oil[i].x<=cow[top].y) { oil[i].y--; ans++; } top++; } } printf("%d\n",ans); return 0; }
這裡貼一份資料生成器
#include <ctime> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 10 #define inf 0x3f3f3f3f using namespace std; int n,m; int main() { srand((unsigned)time(NULL)); int i,j,k; int a,b,c; n=rand()%N+1; m=rand()%4+1; printf("%d %d\n",n,m); for(i=1;i<=n;i++) { a=rand()%N+1; b=rand()%N+a; printf("%d %d\n",a,b); } for(i=1;i<=m;i++) { a=rand()%(N*2)+1; b=rand()%3+1; printf("%d %d\n",a,b); } return 0; }
這裡貼個拍子
#include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define N 3000 using namespace std; int main() { int i,g; system("g++ std.cpp -o std -g"); system("g++ my.cpp -o my -g"); system("g++ rand.cpp -o rand -g"); for(g=1;g<=N;g++) { printf("Case %d : ",g); system("rand>test.in"); clock_t j=clock(); system("my <test.in >my.out"); clock_t k=clock(); printf("my_use : %03dms ",k-j); system("std <test.in >std.out"); printf("std_use : %03dms ",clock()-k); if(system("fc std.out my.out >NULL")==0){puts("result : AC");} else { puts("WAWAWAWAWAWAWAWA!!!!!!!!"); system("start test.in"); return 0; } } puts(""); puts("****,please try again"); return 0; }
拿上述的東西,再找個標程就可以pai了。
下面說一下正確思路。
首先按照順序我們可以知道哪些區間的下界滿足條件,那麼就只需要上界也滿足條件就行了。
因為數遞增,所以如果當前的某個可用區間的上界比當前數小,那麼以後也不可能滿足了,就可以彈出去。
這樣通過優先佇列可以得到一個上界滿足且最小的區間,這個區間則可以被計入答案。
思想說了個大概,沒懂就看程式碼吧。
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 3000
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ans,i;
priority_queue<int>pq;
struct KSD
{
int x,y;
bool operator < (const KSD &a)const{return x==a.x?(y<a.y):(x<a.x);}
}cow[N],oil[N];
int main()
{
// freopen("test.in","r",stdin);
scanf("%d%d,",&n,&m);
for(i=1;i<=n;i++)scanf("%d%d",&cow[i].x,&cow[i].y);
for(i=1;i<=m;i++)scanf("%d%d",&oil[i].x,&oil[i].y);
sort(cow+1,cow+n+1);
sort(oil+1,oil+m+1);
int top=1;
for(i=1;i<=m;i++)
{
while(top<=n&&cow[top].x<=oil[i].x)
pq.push(-1*cow[top++].y);
while(!pq.empty()&&oil[i].y)
{
int ttt=pq.top();
if((-1*ttt)>=oil[i].x)ans++,oil[i].y--;
pq.pop();
}
}
printf("%d\n",ans);
return 0;
}