码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P1250 种树

时间:2018-12-20 18:41:34      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:经典   解决   要求   queue   自己   --   答案   add   name   

我来总结一下最常用的两种办法

1.贪心

2.差分约束

那么我们先来讲,贪心版《种树》

大家可能知道有一个题和这个类似,那个是钉钉子而这个是种树

我们可以借用钉钉子的思路来想,首先这个是让你求最小值,而且每个人都有自己划定的区间,并且他们还要求在这段区间内最少种T棵树。

那么我们既要满足最少种树数,而且要满足每个人的要求。好在的是,题目中说过区间和区间之间可能会有一段重叠,那么我们要抓住这个机会尽可能多的在每一段重复区间内多种树,所以就会产生一个连锁反应,就是上一个重复区间内种的树可能会满足下一个人的要求,那么这个人就可以略过去,以达到最少数的目的。

(以下是贪心代码,体会一下)

#include<bits/stdc++.h>
using namespace std;
const int N = 31000;
int n,m,ans=0;
bool u[N]={0};
struct Edge{
    int x,y,z;
}a[N];
bool cmp(Edge a,Edge b)
{
    return a.y<b.y;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cin>>a[i].x>>a[i].y>>a[i].z;
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int sum=0;
        for(int j=a[i].x;j<=a[i].y;j++)
        if(u[j]) sum++;//统计已有的数量
        if(sum>=a[i].z) continue;//满足就继续
        for(int k=a[i].y;k>=a[i].x;k--)//不满足情况
        {
            if(!u[k])
            {
                u[k]=1;
                sum++;
                ans++;//答案++
                if(sum==a[i].z) break;//直到满足,退出
            }
        }
    }
    cout<<ans;//输出最后答案(即最少的树的数量)
    return 0;
}

 


 

接下来我们讲,差分约束版《种树》

我们都知道差分约束是用于最短路不等式问题的

这里我们利用差分约束解决最短路不等式的性质来看

我们想在区间内种最少的树,所以根据性质

我们可以列出两个差分约束公式

1.sum[x]-sum[y-1]>=c;(这里是指在区间[y,x]中至少种c棵树)

2.0<=sum[x]-sum[x-1]<=1;(这里是指一个单位长度内最多种1棵树)

根据公式,我们可以建边,但是建边是y+1->y=-1而不是y->y+1=1

建好边我们就可以跑一边SPFA啦,最少种树数也就出来了!

(差分约束代码,体会一下)

#include<bits/stdc++.h>
using namespace std;
const int N = 31000;
const int M = 110000;
int n,m;
int dis[N];
bool vis[N];
int head[N],num;
struct Edge{
    int to,next,w;
}s[M];
void add(int u,int v,int w)//根据公式建边
{
    s[++num].w=w;
    s[num].next=head[u];
    head[u]=num;
    s[num].to=v;
}
void spfa(int x)//SPFA经典操(ban)作(zi)
{
    queue<int> q;
    q.push(x);
    for(int i=0;i<=n+1;i++)
        dis[i]=1;
    dis[x]=0;vis[x]=1;
    while(!q.empty())
    {
        int g=q.front();
        q.pop();
        vis[g]=0;
        for(int i=head[g];i!=-1;i=s[i].next)
        {
            int t=s[i].to;
            if(dis[t]>dis[g]+s[i].w)
            {
                dis[t]=dis[g]+s[i].w;
                if(!vis[t])
                {
                    q.push(t);
                    vis[t]=1;               
                }
            }
        }
    }
}
int main()
{
    int a,b,c,minn=123456789;
    memset(head,-1,sizeof(head));
    cin>>n>>m;
    int y=n+1;
    for(int i=0;i<=n;i++) add(y,i,0);
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>c;
        add(b,a-1,-c);
    }
    for(int i=1;i<=n;i++)//建边操作
    {
        add(i-1,i,1);
        add(i,i-1,0);
    }
    spfa(y);
    for(int i=0;i<=n;i++)//取最小值
        minn=min(minn,dis[i]);
    cout<<dis[n]-minn<<endl;
    return 0;
}

烟雨江南,无你何欢!

luogu P1250 种树

标签:经典   解决   要求   queue   自己   --   答案   add   name   

原文地址:https://www.cnblogs.com/xmex/p/10150700.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!