POJ1201
2016-07-12 00:13
375 查看
Problem: Intervals
Description: 给你N个区间,每个区间都有一个C,C表示区间中至少要有C个数字,现在问你至少要多少个数字才能满足所有的区间条件。
Solution_1: 差分约束系统。先看这个问题,如果这些区间都不重叠的话,那么这个问题就很简单。但是并不是这样的,对于区间和问题我们总喜欢表示成这样的形式T−T[a−1]>=C。题中有很多这样的条件,那么是不是很像差分约束系统,这样我们就转化成求0到区间端点的最长路。这样的最长路就是题目中的所求了。但是要注意的是,这里是求最长路,与求最短路不一样,还有当有这些条件是不行的,因为这样无法保证这个图是连通的。我们得从题目中提取些不等式出来,对了就是T[x]−T[x−1]>=0,T[x−1]−T[x]>=−1。有了这些条件后,就是简单的差分约束求最长路了,spfa就好。
Solution_2: 贪心+树状数组,或者再优化些加上并查集。我们知道,对于区间排好序后,我们一个个区间遍历,数字越放到区间右端点的方向越容易被下一个区间覆盖,这样就可以减少数字的数量了。这里用到树状数组是因为要对[1,X]这段区间进行求和。众所周知树状数组是基于二分的,所以速度很快。那么并查集又是怎么回事呢?这也是我看到Discuss中的一个大神用的优化,真的是开眼了,学到了并查集的新用法。这里用并查集是来解决判重问题的,大家注意,如果不用并查集,那么就要用一个used数组来标识这个点是不是有数字了,但是如果用并查集的话我们每次search后把它挂到它前一个点上,那么下次search的时候直接就找到了没有数字并且最后的一个点。这样完美的解决了用used数组要从后先前遍历的问题。
这里有一点要注意,就是区间的排序,之前我一直都是按左端点作为首关键字排序的,所以一直WA。后来在洗澡的时候突然想到了按左端点排序有可能出现反例。看这样的一组数据:
[b]2
1 100 1
4 8 1
我们按左端点排序得到[1,100],[4,8]。由上面的解法,我们会在100这个点填上数字,然后在8这个点填上数字。这样明显不是最优的。那我们按右端点排序得到[4,8],[1,100]。我们在8这个点填上数字,然后查询下[1,100]有1个数字了,因此不用填了,因此最优答案是1。
Code(差分约束):
Code(贪心+树状数组+used数组):
Code(贪心+树状数组+并查集):
Description: 给你N个区间,每个区间都有一个C,C表示区间中至少要有C个数字,现在问你至少要多少个数字才能满足所有的区间条件。
Solution_1: 差分约束系统。先看这个问题,如果这些区间都不重叠的话,那么这个问题就很简单。但是并不是这样的,对于区间和问题我们总喜欢表示成这样的形式T−T[a−1]>=C。题中有很多这样的条件,那么是不是很像差分约束系统,这样我们就转化成求0到区间端点的最长路。这样的最长路就是题目中的所求了。但是要注意的是,这里是求最长路,与求最短路不一样,还有当有这些条件是不行的,因为这样无法保证这个图是连通的。我们得从题目中提取些不等式出来,对了就是T[x]−T[x−1]>=0,T[x−1]−T[x]>=−1。有了这些条件后,就是简单的差分约束求最长路了,spfa就好。
Solution_2: 贪心+树状数组,或者再优化些加上并查集。我们知道,对于区间排好序后,我们一个个区间遍历,数字越放到区间右端点的方向越容易被下一个区间覆盖,这样就可以减少数字的数量了。这里用到树状数组是因为要对[1,X]这段区间进行求和。众所周知树状数组是基于二分的,所以速度很快。那么并查集又是怎么回事呢?这也是我看到Discuss中的一个大神用的优化,真的是开眼了,学到了并查集的新用法。这里用并查集是来解决判重问题的,大家注意,如果不用并查集,那么就要用一个used数组来标识这个点是不是有数字了,但是如果用并查集的话我们每次search后把它挂到它前一个点上,那么下次search的时候直接就找到了没有数字并且最后的一个点。这样完美的解决了用used数组要从后先前遍历的问题。
这里有一点要注意,就是区间的排序,之前我一直都是按左端点作为首关键字排序的,所以一直WA。后来在洗澡的时候突然想到了按左端点排序有可能出现反例。看这样的一组数据:
[b]2
1 100 1
4 8 1
我们按左端点排序得到[1,100],[4,8]。由上面的解法,我们会在100这个点填上数字,然后在8这个点填上数字。这样明显不是最优的。那我们按右端点排序得到[4,8],[1,100]。我们在8这个点填上数字,然后查询下[1,100]有1个数字了,因此不用填了,因此最优答案是1。
Code(差分约束):
#include <iostream> #include <string> #include <queue> #include <string.h> #include <stdio.h> #define MAX(a,b) ((a)>(b)? (a):(b)) #define MIN(a,b) ((a)<(b)? (a):(b)) using namespace std; const int M=4*50000+5; const int INF=0x3f3f3f3f; typedef struct tagNode{ int to,c; int next; }Node; Node map[M]; int head[M]; int top,but,m; int I; int dis[M]; int de[M]; bool used[M]; void add_edge(int from,int to,int c) { map[I].to=to; map[I].c=c; map[I].next=head[from]; head[from]=I++; } bool spfa(int src) { for(int i=0;i<M;i++) dis[i]=-INF,de[i]=0,used[i]=false; queue<int> que; que.push(src); de[src]=1; used[src]=true; dis[src]=0; while(!que.empty()){ int pre=que.front(); que.pop(); used[pre]=false; for(int i=head[pre];i+1;i=map[i].next){ int tmp=map[i].to; if(dis[tmp]<dis[pre]+map[i].c){ dis[tmp]=dis[pre]+map[i].c; if(!used[tmp]){ used[tmp]=true; que.push(tmp); ++de[tmp]; if(de[tmp]>top) return false; } } } } return true; } int main() { while(cin>>m){ int a,b,c; top=-INF; but=INF; I=0; for(int i=0;i<M;i++) head[i]=-1; while(m--){ scanf("%d%d%d",&a,&b,&c); add_edge(a-1,b,c); top=MAX(b,top); but=MIN(a-1,but); } for(int i=but+1;i<=top;i++) add_edge(i-1,i,0), add_edge(i,i-1,-1); spfa(but); cout<<dis[top]<<endl; } return 0; }
Code(贪心+树状数组+used数组):
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #define MAX(a,b) ((a)>(b)? (a):(b)) #define MIN(a,b) ((a)<(b)? (a):(b)) using namespace std; const int M=50000+50; typedef struct tagNode{ int a,b; int c; }Node; int m; int a[M]; bool used[M]; Node qu[M]; int top; bool cmp(Node a,Node b) { if(a.b!=b.b) return a.b<b.b; return a.a<b.a; } int lowbit(int x) { return x&(-x); } void update(int x) { for(int i=x;i<=top;i+=lowbit(i)) ++a[i]; } int find(int x) { int sum=0; for(int i=x;i>0;i-=lowbit(i)) sum+=a[i]; return sum; } int work() { memset(used,false,sizeof(used)); int ans=0; for(int i=1;i<=m;i++){ int sum=find(++qu[i].b)-find(++qu[i].a-1); if(sum<qu[i].c){ int tmp=qu[i].c-sum; ans+=tmp; for(int j=qu[i].b;j>=qu[i].a&&tmp;j--) if(!used[j]) update(j),used[j]=true,--tmp; } } return ans; } int main() { while(~scanf("%d",&m)){ top=-1; for(int i=1;i<=m;i++) scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c), top=MAX(qu[i].b+1,top); memset(a,0,sizeof(a)); sort(qu+1,qu+m+1,cmp); int ans=work(); printf("%d\n",ans); } return 0; }
Code(贪心+树状数组+并查集):
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #define MAX(a,b) ((a)>(b)? (a):(b)) #define MIN(a,b) ((a)<(b)? (a):(b)) using namespace std; const int M=50000+50; typedef struct tagNode{ int a,b; int c; }Node; int m; int a[M]; int p[M]; Node qu[M]; int top; bool cmp(Node a,Node b) { if(a.b!=b.b) return a.b<b.b; return a.a<b.a; } int lowbit(int x) { return x&(-x); } void update(int x) { for(int i=x;i<=top;i+=lowbit(i)) ++a[i]; } int find(int x) { int sum=0; for(int i=x;i>0;i-=lowbit(i)) sum+=a[i]; return sum; } int search(int x) { return x==p[x]? x:p[x]=search(p[x]); } int work() { for(int i=0;i<M;i++) p[i]=i; int ans=0; for(int i=1;i<=m;i++){ int sum=find(++qu[i].b)-find(++qu[i].a-1); if(sum<qu[i].c){ int tmp=qu[i].c-sum; ans+=tmp; for(int now=qu[i].b;tmp;--tmp){ now=search(now); update(now); p[now]=now-1; --now; } } } return ans; } int main() { while(~scanf("%d",&m)){ top=-1; for(int i=1;i<=m;i++) scanf("%d%d%d",&qu[i].a,&qu[i].b,&qu[i].c), top=MAX(qu[i].b+1,top); memset(a,0,sizeof(a)); sort(qu+1,qu+m+1,cmp); int ans=work(); printf("%d\n",ans); } return 0; }
相关文章推荐
- dex2oat: dex2oat
- OpenGL学习脚印:模型加载初步-加载obj模型(load obj model)
- POJ 2226 Muddy Fields(二分图匹配)
- Vue.js学习 Item15 – 构建大型web应用
- gcc和g++的区别
- 一个网站的成长
- SAE部署Django1.6+MySQL
- POJ-3356-AGTC
- Oracle11G安装
- 图解机顶盒数据处理流程
- tarjan缩点模板 poj 2186
- Hibernate-----@DynamicInsert、@DynamicUpdate
- 腾讯Bugly异常监控集成
- Django+MySQL安装配置详解(Linux)[更新为1.8.2版]
- 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
- 谈谈jquery的事件名称和命名空间
- Vue.js学习 Item14 – 过滤器与自定义过滤器
- 基于按钮点击事件的弹窗
- 机器学习算法比较
- iOS学习笔记