【序列长度】解题报告
来源:互联网 发布:中国家庭金融调查数据 编辑:程序博客网 时间:2024/05/19 12:12
4.序列长度
【问题描述】
有一个整数序列,我们不知道她的长度是多少(即序列中整数的个数),但我们知道在某些区间中至少有多少个整数,用区间 [ai,bi,ci]来描述它,[ai,bi,ci]表示在该序列中处于[ai,bi]这个区间的整数至少有ci个。现在给出若干个这样的区间,请你求出满足条件的最短序列长度是多少。如果不存在则输出 -1。
【文件输入】
第一行包括一个整数n(n<=1000),表示区间个数;
以下n行每行描述这些区间,第i+1行三个整数ai,bi,ci,由空格隔开,其中0<=ai<=bi<=1000而且1<=ci<=bi-ai+1。
【文件输出】
文件输出只有一个整数表示满足要求序列长度的最小值。
【样例输入】
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1【样例输出】
6
提示:
其中两个合法序列分别为(3,5,7,8,9,10)(3,4,6,8,9,10),长度都为6,不可能有比6更短的合法序列了.
注意:序列中不能有相同数字.
这道题有点难度,只有biamgo和汪维正用了最优解法。查分约束系统。(这道题还有贪心方法、动规方法(不正确))
//===============================================================
把问题抽象成一个数组T。
题中给出很多的限制条件:
用前缀和简化为
再类比spfa中,u为松弛v的点
因此我们可以把没个S抽象为一个点,
从u到v建立一条权值为-map[u,v]的边。
这样做是错误的。还有一个隐藏的限制条件
这个是容易想到的,
因此还需要加两条边。
代码实现上,有两种方案,一是用一个超级源,二是首先把所有的元素入队,我采用了第二种方法,因为此题中0号节点是有实际意义的,因此只好用m+1来表示空。
另外一点,就是差分约束不能够像spfa那样手动对初始点进行松弛,因此应该把每个点的d值设为相同,最后输出两个d的差,只表示相对高度。
一开始一直错在加边应该是(a[i],b[i]-1),我写成(a[i],b[i])了。
//===============================================================
spfa中如果存在一个负权回路,就会对一个点无限次地松弛。
因为一个点最多被松弛n次(易证),如果超过n次说明存在负权回路,即无解
//================================================================
//#include <iostream>//using std::cout;//using std::cin;#include <cstdio>#include <bitset>const long oo = 0x7fff0000;std::bitset<1002> q;long a[1002];long b[1002];long c[1002];long n;long s[1002];bool used[1002];long l=0;long r=0;long que[1000002];long m = 0;long count[1002];struct node{long index;long data;node* next;};node* bian[100002];void spfa(){while (l<r){long now = que[++l];used[now] = false;node* ths = bian[now];while (ths){long i = ths->index;if (s[i] > s[now]+ths->data){count[i]++;if (count[i]>n){printf("-1");exit(0);}s[i] = s[now]+ths->data;if (!used[i]){used[i] = true;que[++r] = i;}}ths = ths->next;}}}void insert(long a,long b,long c){node* tmp = new node;tmp->index = b;tmp->data = c;tmp->next = bian[a];bian[a] = tmp;}int main(){freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);scanf("%ld",&n);for (long i=1;i<n+1;i++){scanf("%ld%ld%ld",a+i,b+i,c+i);//map[b[i]][a[i]-1] = -c[i];insert(b[i],a[i]-1,-c[i]);m >?= b[i];m >?= a[i];}for (long i=1;i<m+1;i++){//map[i][i-1] = 0;//map[i-1][i] = 1;insert(i,i-1,0);insert(i-1,i,1);}insert(0,m+1,0);insert(m+1,0,1);for (long i=0;i<m+1;i++){que[++r] = i;}spfa();printf("%ld",s[m]-s[m+1]);return 0;}
贪心:
按照右边界的升序排列,
从A点向左必然满足数列上数量为c[i],
然后从B点向左,必然首先满足上一个条件,然后如果不够再继续在空隙里面填,
依此类推。填的时候尽量从右节点开始向左填,尽量让多个区间共享?
#include <iostream>using std::cout;//using std::cin;#include <cstdio>#include <bitset>const long oo = 0x7fff0000;struct node{long a;long b;long c;};node qj[1002];std::bitset<1002> q;long n;int bigger(const void* a,const void* b){node* aa = (node*)a;node* bb = (node*)b;if (aa->b>bb->b)return 1;if (aa->b<bb->b)return -1;return 0;}int main(){freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);scanf("%ld",&n);for (long i=1;i<n+1;i++){scanf("%ld%ld%ld",&qj[i].a,&qj[i].b,&qj[i].c);}qsort(qj+1,n,sizeof(node),&bigger);if (n==0){printf("-1");return 0;}if (n==1){printf("%ld",qj[1].c);return 0;}//if (n==5){printf("6");return 0;}for (long i=1;i<n+1;i++){long ss = qj[i].c;for (long j=qj[i].a;j<qj[i].b+1;j++){if (q.test(j)){ss--;}}long tt = qj[i].b;while (ss>0){while (tt>=0&&q.test(tt)){--tt;}if (tt<0){printf("-1");return 0;}q.set(tt);ss--;}}printf("%ld",q.count());return 0;}
- 【序列长度】解题报告
- 波动序列解题报告
- 字符序列 解题报告
- [Hnoi2016]序列 解题报告
- 序列和解题报告
- TYVJ1193 括号序列解题报告
- UVA1423 猜序列 解题报告
- 【最大子序列和】解题报告
- [CODEVS1283]等差子序列解题报告
- 解题报告:乘积最大子序列
- foj 2170 花生壳的序列 解题报告
- [bzoj3744]Gty的妹子序列 解题报告
- codevs 2622 数字序列 DP 解题报告
- 校内赛 不正常序列 堆 解题报告
- CodeVS3657 括号序列 解题报告【区间DP】
- 洛谷 1631 序列合并 堆 解题报告
- 连续序列 最大乘积解题报告
- POJ 1458(最长公共子序列 动态规划) 解题报告
- 数据库
- Ubuntu中常用的工具安装
- 在java程序中使用linux命令(脚本)
- 获取本地IP地址
- Eclipse中servlet显示无法导入javax.servlet包问题的解决方案
- 【序列长度】解题报告
- 一步一步写算法(之图创建)
- Ubuntu10.04 ---- 内核模块
- jvm学习内容
- Socket的select模型(转)
- 查看访问次数
- 用jquery解析JSON数据的方法
- set --设置位置参数
- C++汉诺塔问题。