CF-515div2-B-有趣的貪心(挑戰的P46)- Heaters
阿新 • • 發佈:2019-01-10
題目傳送門
題意:
在一個數列裡面有0,1。0代表沒有heater,1代表有heater.每個heater都有相同的半徑r。要你開啟最少的heater是的每個地方都能被heat到。
注意1本身也是沒有heater的。所以要考慮1.昨天我就是這裡理解錯了,所以一直debug都沒有改出來。正確理解題意是多麼重要的一件事。現在終於該出來了,我感慨萬千。debug的歷史。
思路:
首先這與挑戰P46的題目差不多。可以先去那裡看一下。
首先,貪心從最右端(半徑所在的範圍)找heater,[pos+1,pos+r-1],從pos+r-1開始遍歷到pos+1,如果有直接用,否則開啟一個沒有開啟的1.如果這個方向不行。那麼去左端找,[pos-r+1,pos-1],從pos-1開始遍歷到pos-r+1.如果有已經開啟的1,就進步下一步。否則注意了,如果你先在的中心點是1,那麼前面都不行後(右端不行,左端沒有現成的),那麼就開啟本身,而不是在左端新開啟一個。如果是0的話,那只有在左端新開啟一個了。
具體細節看程式碼註釋。‘
這種題是一種套路,要麼從左往右,要麼從右往左,要麼兩者。
提供兩個版本,第一個複雜長了點,第二個簡化版。
AC code: #include<iostream> #include<cstdio> #include<vector> #include<bitset> #include<stack> #include<set> #include<queue> #include<map> #include<cmath> #include<string> #include<cstring> #include<ctime> #include<fstream> #include<cstdlib> #include<algorithm> using namespace std; //#define pii pair<int, int> #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define per(i,a,b) for(int i=a;i<=b;i++) #define rep(i,a,b) for(int i=a;i>=b;i--) #define all(x) x.begin(),x.end() #define PER(i,x) for(auto i=x.begin();i!=x.end();i++) #define PI acos(-1.0) #define INF 0x3f3f3f3f typedef long long LL; typedef pair<int,int> pii; const double eps=1.0e-5; const int maxn=1e3 + 10; int dx[4] = {0,0,-1,1}; int dy[4] = {1,-1,0,0}; int n = 0,r = 0; int a[maxn],pos[maxn]; bool vis[maxn]; void solve(){ fill(vis,vis+maxn,false); int ans = 0,fg = 0,flag = 0; for(int i = 1;i <= n;){ fg = 0; for(int j = max(i-1,1);j >= max(i-r+1,1);--j){//首先遍歷該點前面的點是否有heater if(vis[j] == true){ //如果有,i++,重新開始 i++; fg = 1; break; } } if(fg == 1){ continue; } for(int j = min(i+r-1,n);j >= i+1;--j){//然後從他的後面找heater,從最遠的地方開始找 if(a[j] == 0 ){//0直接跳過 continue; } if(vis[j] == true){//找到一個heater,則跳到j+r i = j + r-1+1; fg = 1; break; } if(vis[j] == false){//找到一個沒開的1,那麼就開啟 ans++; vis[j] = true; i = j + r-1+1; fg = 1; break; } } if(fg == 1){ continue; } //如果後半部分沒有找到,就只有去前面開啟1了 for(int j = max(i-1,1);j >= i-r+1 && j >= 1;--j){ if(a[j] == 0){ continue; } if(vis[j] == true){//找到一個已經開啟的,就跳過 i = j + r-1+1; fg = 1; break; } if(vis[j] == false && a[i] != 1){//找到一個沒開的1,但是本身不能是1, //因為本身是1的話 ,不如點開本身,就不開前面的1了 ans++; vis[j] = true; i = j + r-1+1; fg = 1; break; } } if(a[i] == 1 && fg == 0){//如果後面沒有找到1,並且前面沒有已經開啟的1, ans++;//那麼就開啟本身的1 vis[i] = true; i++; fg = 1; continue; } if(fg == 0){//如果都找不到,那麼這裡不能被heat flag = 1; break; } } printf("%d\n",flag == 1 ? -1 : ans); } int main(){ #ifndef ONLINE_JUDGE //freopen("a.txt","r",stdin); #endif while(~scanf("%d %d",&n,&r)){ per(i,1,n){ scanf("%d",&a[i]); } solve(); } return 0; }
簡單版本:
AC code: #include<bits/stdc++.h> using namespace std; const int maxn = 1e3 + 10; int a[maxn]; int n = 0,r = 0; int main(){ while(~scanf("%d %d",&n,&r)){ for(int i = 1;i <= n;++i){ scanf("%d",&a[i]); } int fg = 0; int last = 1,pre = 1; int ans = 0; while(last <= n){ int flag = -1; for(int j = max(last-r+1,1);j <= min(last+r-1,n);++j){ if(a[j] == 1){ flag = j; } } if(flag == -1){ fg = 1; printf("-1\n"); break; } ans++; last = flag + r ; if(last == pre){ last += 1; } pre = last; } if(fg == 1){ continue; } printf("%d\n",ans); } return 0; }