贪心算法整理

贪心:求局部最优以得到整体最优,贪心算法可以依赖于以前做出的选择,但不依赖于将来的选择,以迭代的方式做出相继的贪心选择,逐步小化问题。

1.最大值最小化
uva714
题目的意思就是给出m个数,分成k组,只能连续的分成一组。求分组中和的最大值最小。
思路:二分枚举最大值,然后划分的每一组尽量接近这个枚举的值,最大值尽量小。
这道题的核心部分是二分枚举,贪心主要体现在尽量靠近枚举的值


#include
#include
#include
#include
#include
using namespace std;
const int maxn = 505;
long long l, r, n, group;
int a[maxn];
int vis[maxn];
bool judge(long long x) {

    int k = 1, i;
    long long sum = 0;
    for(i=0; iif(sum + a[i] <= x) {

            sum += a[i];
        }else {

            k++;
            sum = a[i];
        }
        if(k>group) return false;
    }
    return true;
}

void print() {


    memset(vis, 0, sizeof(vis));
    int k = 1,i;
    long long sum=0;
    for(i=n-1; i>=0; i--) {

        if(sum+a[i]<=l) {
            sum += a[i];
        }else {

            k++;
            sum = a[i];
            vis[i] = 1;
        }
    }
    for(i=0; i1&&kif(!vis[i]) {

            vis[i]=1;
            k++;
        }
    }
    for(i=0; iif(i!=n-1) {

            printf("%d ", a[i]);
            if(vis[i]) {

                printf("/ ");

            }
        }
        else printf("%d\n", a[i]);
    }
}
int main() {

    int kase;
    scanf("%d", &kase);
    while(kase--) {

        long long sum = 0;
        long long m = 0;
        int i;
        scanf("%d%d", &n, &group);
        for(i=0; iscanf("%d", &a[i]);
            sum += a[i];
            m = a[i]>m?a[i]:m;
        }
        l=m, r=sum;
        while(r>l) {
            long long mid = (l+r)/2;
            if(judge(mid)) {
                r=mid;
            }else l=mid+1;
        }
        print();

    }
}

2.尽量少的资源消耗
uva10382
有一块草坪,长为l,宽为w,在它的水平中心线上有n个位置可以安装喷水装置,各个位置上的喷水装置的覆盖范围为以它们自己的半径ri为圆。求出最少需要的喷水装置个数。
区间覆盖问题
代码:

#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 10005;
int n;
double l, w;
double p, r;
int num;
double cal() {
    return sqrt(r*r-w*w/4.0);
}
struct node {
    double le, ri;
    bool operator<(const node& c)const {
        return leint main() {
    while(scanf("%d%lf%lf", &n, &l, &w) != EOF) {
        num=0;
        for(int i=0; iscanf("%lf%lf", &p, &r);
            if(r<=w/2) continue;
            double t=cal();
            arr[num].le=p-t;
            arr[num].ri=p+t;
            num++;
        }
        double le=0, ri=0;
        int flag=0, ans=0;
        sort(arr,arr+num);
        if(arr[0].le<=0) {
            int i=0;
            while(iint j=i;
                while(jif(riif(i==j) break;
                le = ri;
                i=j;
                ans++;
                if(ri>=l) 
                {
                    flag = 1;
                    break;
                }
            }
        }
        if(flag) printf("%d\n", ans);
        else printf("-1\n");

    }
    return 0;
}

uva10670
公司要你要完成N份任务,但是你是不可能全部完成的,所以需要雇佣别人来做,做到剩下M份时,自己再亲自出马。现在有个机构,有两种付费方式,第一种是每付A元帮你完成1份,第二种是每付B元帮你完成剩下任务的一半。

#include
#include
#include
#include
using namespace std;
const int maxn = 105;
char str[maxn];
int n, m, l;
struct node {

    char name[maxn];
    int half;
    int per;
    int money;
}p[maxn];

void deal (int j) {

    int k = 0,i;
    for (i = 0; i < strlen (str); i++) {

        if (str[i] != ':')
            k++;
        else
            break;  
    }
    memcpy (p[j].name, str, sizeof (str));
    p[j].name[k] = '\0';

    int sum = 0;
    for (i = k + 1; i < strlen (str); i++) {

        if (str[i] != ',')
            sum = sum * 10 + str[i] - '0';
        else {

            p[j].per = sum;
            sum = 0;
        }
    }
    p[j].half = sum;   
}

void cal(int cur) {

    int num = n;
    int sum = 0;
    while(num/2>=m && (p[cur].per*(num-num/2))>=p[cur].half) {
        sum += p[cur].half;
        num/=2;
    }
    sum += (num-m)*p[cur].per;
    p[cur].money = sum;
}


int cmp (const node & x, const node & y) {

    if (x.money < y.money)
        return true;
    else if (x.money > y.money)
        return false;
    else return strcmp (x.name, y.name) < 0 ? true: false;
}
int main() {

    int kase;
    int cas = 1;
    scanf("%d", &kase);
    int i, j;
    while(kase--) {
        printf("Case %d\n", cas++);
        scanf("%d%d%d", &n, &m, &l);
        getchar();
        for(i=0; ifor (j = 0; j < l ; j++)
            printf ("%s %d\n", p[j].name, p[j].money);

    }

    return 0;
}

3.多机调度问题
4.最小生成树
uva10034:模板题
题目:把所有的点连起来最短
1. Kruskal

#include
#include
#include
#include
#include 
using namespace std;
const int N = 105;
double x[N], y[N];
struct edge {
    double x, y, d;
}e[N*N];
int f[N];
double ans;
double dis(double x1, double y1, double x2, double y2) {
    return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
int n;
int num;
int cmp(edge a, edge b) {
    return a.d < b.d;
}
int find(int x) {
    return (x == f[x])?x:find(f[x]);
}
void uni(int a, int b) {

    f[a] = find(b);
}

void ki() {
    ans = 0;
    for(int i=0; ifor(int i=0; iint a = find(e[i].x);
        int b = find(e[i].y);
        if(a != b) {
            uni(a,b);
            ans += e[i].d;
        }
    }
    printf("%.2lf\n", ans);
}

int main() {
    int cas; 
    scanf("%d", &cas);
    while(cas--) {
        num = 0;
        scanf("%d", &n);
        for(int i=0; iscanf("%lf%lf", &x[i], &y[i]);
        }
        for(int i=0; ifor(int j=0; jif(i != j) {
                e[num].x = i;
                e[num].y = j;
                e[num++].d = dis(x[i], y[i], x[j], y[j]);
                }
            }
        sort(e, e+num, cmp);
        ki();
        if(cas) printf("\n");
    }

    return 0;
}

prim

#include
#include
#include
#include
#include
using namespace std;
const int inf = 0xFFFFFFF;
double x[105], y[105], g[105][105];
int vis[105];
double d[105];
double ans;
int n;
double dis(double x1, double y1, double x2, double y2) {
    return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
}
void prim() {
    for(int i=0; i0][i];
    d[0] = 0;
    memset(vis, 0, sizeof(vis));
    double m;
    int x = 0;

    for(int i=0; ifor(int j=0; jif(d[j]if(m==inf) break;
        ans += m;
        vis[x] = 1;
        for(int j=0; jif(d[j]>g[j][x] && !vis[j]) d[j] = g[j][x];//集外任意一点到已经纳入集合内的点在重调一次距离
        }
    }
}

int main() {
    int cas;
    scanf("%d", &cas);
    while(cas--) {
        memset(g, 0, sizeof(g));
        scanf("%d", &n);
        for(int i=0; iscanf("%lf %lf", &x[i], &y[i]);
        }
        for(int i=0; ifor(int j=0; j0;
        prim();
        printf("%.2lf\n", ans);
        if(cas) printf("\n");
    }
    return 0;
}

5.最短路径

#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n, m, s, d;
const int maxn = 200005;
const int inf = 0x3f3f3f3f;
struct node {
    int n,w;
    node(){}
    node(int a,int b) {
        n=a;
        w=b;
    }
    bool operator<(const node& q)const {

        return w>q.w;
    }
};
vectorv[maxn];
int dis[maxn];
void dijkstra() {
    int i;
    int ans = 0;
    dis[s] = 0;
    priority_queueq;
    q.push(node(s,0));
    while(!q.empty()) {

        node u = q.top();
        q.pop();
        for(i=0; i//遍历每个点
            if(dis[temp.n]>dis[u.n]+temp.w) {
                dis[temp.n] = dis[u.n]+temp.w;//w是从u.n到temp.n的权重
                q.push(temp);
            }
        }

    }
}
int main() {
    int kase;
    int t=1;
    int i,j;
    int a,b,c;
    scanf("%d", &kase);
    while(kase--) {
        scanf("%d%d%d%d", &n,&m,&s,&d);
        for(i=0; i<=n; i++) v[i].clear();
        memset(dis, inf, sizeof(dis));
        for(i=0; iscanf("%d%d%d", &a,&b,&c);
            v[a].push_back(node(b,c));
            v[b].push_back(node(a,c));

        }
        dijkstra();
        printf("Case #%d: ", t++);  
        if (dis[d] < inf)  
            printf("%d\n", dis[d]);  
        else  
            printf("unreachable\n");  
    }
    return 0;
}

你可能感兴趣的:(贪心)