貪心思維 專題記錄 2017-7-21
A、UVa 10382 - Watering Grass
題目大意: 有一塊草坪,長為l,寬為w,在它的水平中心線上有n個位置可以安裝噴水裝置,各個位置上的噴水裝置的覆蓋範圍為以它們自己的半徑ri為圓。求出最少需要的噴水裝置個數。 思路 :轉化一下 將二維降成一維 d = sqrt(1.0*r*r-w*w/4.0) 接著就是區間覆蓋問題了#include <bits/stdc++.h> using namespace std; const int maxn = 10000+10; typedef pair <int,int > pii; typedef pairA<double ,double >pdd; struct p{ double a,b; }; int n; double l,w; pdd s[maxn]; bool cmp(const pii &x,const pii &y) { if(x.first != y.first) return x.first < y.first; return x.second < y.second; } int solve() { int cnt = 0; doublelast = 0,far = 0; for(int i=0;i < n;i++) { if(last >= l) return cnt; if(s[i].first <= last) far = max(far,s[i].second); else if(s[i].first > last) { cnt++; last = far; if(s[i].first <= last) far= max(far,s[i].second); else return -1; } } if(last < l && far >= l) return cnt+1; if(far < l ) return -1; return cnt; } int main () { while( scanf("%d%lf%lf", &n, &l, &w) != EOF) { for(int i=0;i < n;i++) { double pos , r; scanf("%lf %lf",&pos,&r); double d = sqrt(1.0*r*r-w*w/4.0); s[i].first = pos - d, s[i].second = pos + d; } sort(s,s+n,cmp); cout<< solve()<<endl; } return 0; }
B、UVa 10905 - Children‘s Game
題目大意:
給出n個數字 輸出組合最大的
思路 :兩個數 如果位數相同 直接比較大小 ;
如果不同 就兩個數換位置 看哪個大;
#include <iostream> #include <algorithm> #include <string> #include <string.h> using namespace std; string s[60]; bool cmp(const string &a,const string &b){ if(a.size() == b.size()){ return a < b; } string t1 = a+b, t2=b+a; return t1 < t2; } int main() { int n; while (cin >> n && n) { for(int i=0;i<n;i++) cin >> s[i]; sort(s,s+n,cmp); for(int i=n-1;i>=0;i--) cout<< s[i]; cout<<endl; } return 0; }B
C、UVA 11134 Fabled Rooks
題目大意:
在一個n*n(1<=n<=5000)的棋盤上放置n個車,每個車都只能在給定的一個矩形裏放置,使其n個車兩兩不在同一行和同一列,判斷並給出解決方案
思路 :把題目裏的二維的改成一維的,就是有一行,讓你放,每個車可以放一個區間[li,ri],讓你找一種方案,使得每個車不在同一個格子裏。然後就可以這樣貪心:枚舉每個格子,記為i,那麽是不是所有滿足左端點li <= i的裏頭,挑一個右端點盡可能小的來放在這一個格子裏面?,因為右端點越大,它後面可 能可以放的格子越多,越小,可放的格子越小,所以我們這樣貪心的來放
#include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; const int maxn = 5000 + 10; const int INF = 0x3f3f3f3f; typedef long long LL; typedef pair <int ,int > pii; typedef pair <LL ,LL >pLL; typedef unsigned long long ull; struct node { int left,ri,order; bool operator < (const node & l)const{ if(left != l.left) return left < l.left; return ri < l.ri; } } x[maxn],y[maxn]; int X[maxn],Y[maxn]; bool solve (int n,node s[],int S[]) { sort(s,s+n); priority_queue <pii,vector<pii>,greater<pii> > q; int cnt =0, ret = 0; for(int i=1;i <= n;i++) { while (cnt < n && s[cnt].left <= i)//不停找左邊界 { q.push( pii(s[cnt].ri,s[cnt].order) );//右邊的邊界 壓進來 cnt++; } if(q.size() == 0) return 0; pii p =q.top(); if(p.first < i) return 0; //右邊界如果小於i的話 已經找不到了 S[p.second] = i; q.pop(); ret++; // cout << ret <<endl; } return ret == n; } int main () { int n; while (~scanf("%d",&n) && n) { for(int i=0;i < n;i++) { scanf("%d%d%d%d",&x[i].left, &y[i].left , &x[i].ri, &y[i].ri); x[i].order = y[i].order = i; } if( solve (n,x,X) && solve (n,y,Y) ) { for(int i=0; i < n;i++) { printf("%d %d\n",X[i],Y[i]); } } else printf("IMPOSSIBLE\n"); } return 0; }C
D、uva 11100 - The Trip
題目大意:
有很多包,已知包的區別只在於高度不一樣,小包可以裝到大包裏邊,求最終剩下多少個包,並輸出沒一個組合
思路 :相同的包裹沒辦法在一個組裏面 所以最後剩下的包 即為最大的 相同的包的 個數 k;
然後按照大小排序,然後每隔k個間隔選一個數 構成一個組別 example:x,x+k,.....x+t*k (x+t*k <= n)
#include <bits/stdc++.h> using namespace std; const int maxn = 10000+10; int s[maxn]; int num[1000010]; int main () { int n; while (cin >> n && n){ int k = 0; memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ cin >> s[i]; num[s[i]] ++; k = max(k,num[s[i]]); } cout<< k <<endl; sort(s,s+n); for(int i=0;i<k;i++) { cout<< s[i]; for(int j=k+i;j<n;j+=k){ cout<< " "<<s[j]; } cout<< endl; } //cout<<endl; } return 0; }D
E、UVa 11384 - Help is needed for Dexter
題目大意:
給你1~n,n個連續的整數,每次可以從裏面取出人一個數字減去一個任意數, 問最少操作多少次可以全變成0。
思路 : 本題思路就是每次都找中間的那個 然後直接減掉 比如 1 2 3 4 5 就找 3 然後剪掉3 就變成 1 2 0 1 2
然後 接著就變成了 1 2 依次遞減
#include <bits/stdc++.h> using namespace std; int main () { int n; while (cin >> n) { int cnt = 0; while (n > 0 ) { n/=2; cnt++; } cout<<cnt<<endl; } return 0; }E
F、UVa 10795 A Different Task
題目大意:
有三個柱子 然後給你初始 和 目標的盤子所在的柱子 求最小移動次數
思路 :
參照 http://www.cnblogs.com/arbitrary/archive/2012/12/11/2813245.html
就是 首先找最大不在目標柱子上的盤子K 之前已經就位了 不用動
然後 轉換成 一個大概的狀態: 只有K 在 初始盤 然後 其余的k-1個都在中轉盤上 然後 想把K 移動到 除了第三個盤上
所以問題變成答案=從初始局面移到參考局面步數+目標局面移到參考局面步數+1;
#include <iostream> #include <cstring> #include <string.h> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; const int mod = 1e9 + 7; const int maxn = 70; const int INF = 0x3f3f3f3f; const double eps = 1e-8; typedef pair<int, int>pii; typedef pair<double, double>pdd; typedef long long LL; typedef unsigned long long ull; int s[maxn],e[maxn]; LL f(int *p,int i,int final) { if ( i == 0) return 0; if(p[i] == final) return f(p,i-1,final); return f(p,i-1,6-final-p[i]) + (1LL << (i-1));//將i-1個盤子 從中轉柱子 移動到本來的位置 所以加上2的i-1次方 } int main() { int n; int Case =1; while (~scanf("%d",&n), n) // 有n個盤子 { for(int i=1;i<=n;i++) cin >> s[i]; for(int i=1;i<=n;i++) cin >> e[i]; int k = n; while(s[k] == e[k] && k) k--; LL ans = 0; if( k != 0) { int other = 6-s[k] - e[k];//找到中轉的柱子 ans = f(s,k-1,other) + f(e,k-1,other) + 1;//把1到k-1移到中轉柱子上 然後再將k移動到目標柱子 } printf("Case %d: %lld\n",Case++,ans); } return 0; }F
G、UVA 11520 - Fill the Square
題目大意:
給你一個n*n的格子,有些裏面有大寫字母,用大寫字母填滿格子,相鄰的格子中字母不相同, 並且使得從上到下,從左到右的字母字典序最小。
思路 : 構造。將格子從上到下,從左到右編號,然後按編號填充,避免沖突即可,這樣一定最小。
(如果,該方案不是最小,那麽之前一定會選擇更小的方案,而不是本方案)
#include <iostream> #include <cstring> #include <iostream> #include <cstdio> using namespace std; const int maxn = 15; char s[maxn][maxn]; int main () { int t,n; cin >> t; //100 * 100 *26 for(int a=1;a<=t;a++) { cin >> n; for(int i=0;i<n;i++) cin >> s[i]; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(s[i][j] == ‘.‘) { for(char k = ‘A‘;k<=‘Z‘;k++) { bool ok = 1; if(i > 0 && s[i-1][j] == k) ok=0; if(i < n-1 &&s[i+1][j] == k ) ok=0; if(j > 0 && s[i][j-1] == k) ok=0; if(j< n-1 && s[i][j+1] == k) ok = 0; if( ok ) { s[i][j] = k; break; } } } } } printf("Case %d:\n",a); for(int b=0;b<n;b++) cout<< s[b]<<endl; } return 0; }G
貪心思維 專題記錄 2017-7-21