1. 程式人生 > >貪心思維 專題記錄 2017-7-21

貪心思維 專題記錄 2017-7-21

區間覆蓋 pair lap ons break left bits 最小 ()

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 pair 
<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; double
last = 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; }
A

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