建设微网站,理财p2p网站开发,如何 做网站跳转,爱站工具想说超人下拉系统附另一#xff1a;此类问题选题总结#xff1a;https://blog.csdn.net/qq_41289920/article/details/81001357
题干#xff1a;
会场安排问题时间限制#xff1a;3000 ms | 内存限制#xff1a;65535 KB难度#xff1a;4描述学校的小礼堂每天都会有许多活动#xff0c;有…附另一此类问题选题总结https://blog.csdn.net/qq_41289920/article/details/81001357
题干
会场安排问题时间限制3000 ms | 内存限制65535 KB难度4描述学校的小礼堂每天都会有许多活动有时间这些活动的计划时间会发生冲突需要选择出一些活动进行举办。小刘的工作就是安排学校小礼堂的活动每个时间最多安排一个活动。现在小刘有一些活动计划的时间表他想尽可能的安排更多的活动请问他该如何安排。输入第一行是一个整型数m(m100)表示共有m组测试数据。每组测试数据的第一行是一个整数n(1n10000)表示该测试数据共有n个活动。随后的n行每行有两个正整数Bi,Ei(0Bi,Ei10000),分别表示第i个活动的起始与结束时间BiEi)输出对于每一组输入输出最多能够安排的活动数量。每组的输出占一行样例输入221 1010 1131 1010 1111 20样例输出1
2
提示注意如果上一个活动在t时间结束下一个活动最早应该在t1时间开始解题报告以下给出三种方法只有一种是正确的 。1.按照start从小到大排同时end从小到大然后0~n-1遍历。2.按照end从大到小排同时start从大到小排然后0~n-1遍历。3.按照end从小到大排同时start从小到大排其实start无所谓然后0~n-1遍历。不难看出只有3是成立的。
证明首先1和2肯定是绑定的即如果成立均成立如果不立均不立。因为其实模拟一组样例画出图来之后倒着看1和2的方法是一模一样的或者说在1中找到一组样例否定掉这种方法那么样例倒过来之后也可以否定掉第二种方法。
所以下证方法1是错误的证明是错误的方法很简单找一个特例否定掉他下面给的是排完序后的1,56,1007,911,1315,16
显然。
下证方法3是正确的
************************************************************************************经典的区间贪心问题。将每个区间按右端点进行排序每次第一个区间一定要选然后重新确定起点再第一个一定要选。
证明如下设前两个区间为a1, b1, a2, b2且b1b2(即已经按b排好序了)
1当b1a2
这种情况区间1和区间2不冲突,这样做一定是对的
2当第一个区间与其他区间起冲突了而且第一个区间可能与很多区间同时起冲突了。但是所以这些起冲突的区间只能取一个。对于第一个区间要么取要么不取两个情况
1如果最后答案里有这个区间先取后取一个样的那么还不如第一下就取了
2假设最后答案里没有这个区间我们能推出矛盾那不就说明“最后答案里没有这个区间“这个假设是错的。因为刚开始起冲突的那些区间一定只能选一个如果你选了其他可是这个区间一定可以被第一个替换掉所以最后答案里又会出现第一个区间。证明选自https://blog.csdn.net/shiwaigaoren12345/article/details/50767381
所以是正确的。
*************************************************************************************
下面给出三种方法的代码
方法1
#includeiostream
#includecstdio
#includealgorithm
using namespace std;struct Node {int s,e;
} node[10000 5];
//贪心排序起点做不出来需要排end
bool cmp(const Node a, const Node b) {if(a.s!b.s) return a.sb.s;else return a.eb.e;
}
int main()
{int m,n;scanf(%d,m);while(m--) {scanf(%d,n);for(int i 0; in; i) {scanf(%d %d,node[i].s,node[i].e); }sort(node,noden,cmp);int cursnode[0].s;int curenode[0].e;int ans1;int i 1;while(in) {if(node[i].snode[i-1].s) {cursnode[i].s;curemin(cure,node[i].e);continue;}if(node[i].scure) {ans;cur}}}return 0 ;
}
没有写完因为写不动了即 很早的发现了错误。。
方法2
#includeiostream
#includecstdio
#includealgorithm
using namespace std;struct Node {int s,e;
} node[10000 5];
//贪心排序起点做不出来需要排end 这样做从大到小排 依然是错的因为和排start一样了啊。。你倒着看看 画个图
bool cmp(const Node a, const Node b) {if(a.e!b.e) return a.eb.e;else return a.sb.s;
}
int main()
{int m,n;
// freopen(in.txt,r,stdin);scanf(%d,m);while(m--) {scanf(%d,n);for(int i 0; in; i) {scanf(%d %d,node[i].s,node[i].e); }sort(node,noden,cmp);
// for(int i 0; in; i) {
// printf(%d %d\n,node[i].s,node[i].e);
// }int cursnode[0].s;int curenode[0].e;int ans1;int i 1;while(in) {if(node[i].enode[i-1].e) {curenode[i].e;cursmax(curs,node[i].s);i;continue;}if(node[i].ecurs) {ans;curenode[i].e;cursnode[i].s;i;}else {i;}}printf(%d\n,ans);}return 0 ;
}
这种方法仔细分析会发现就是第一种方法。。方法3ac代码
#includeiostream
#includecstdio
#includealgorithm
using namespace std;struct Node {int s,e;
} node[10000 5];
//贪心排序起点做不出来需要排end 并且是小到大排
bool cmp(const Node a, const Node b) {if(a.e!b.e) return a.eb.e;else return a.sb.s;//其实这句就没用了
}
int main()
{int m,n;
// freopen(in.txt,r,stdin);scanf(%d,m);while(m--) {scanf(%d,n);for(int i 0; in; i) {scanf(%d %d,node[i].s,node[i].e); }//养成输入完接着就排序的好习惯若是放在while前面对于本题那就错了 sort(node,noden,cmp);int cursnode[0].s;//其实curs全程没用可以删掉。 int curenode[0].e;int ans1;int i 1;while(in) {//如果是 if(node[i].enode[i-1].e)就错了、、、 //并且这个if可以删掉、、if(node[i].ecure) {curenode[i].e;cursmax(curs,node[i].s);i;continue;}if(node[i].scure) {ans; curenode[i].e;//思想的精华cursnode[i].s;//curs依旧是没啥用、、、 i;}else {i;}}printf(%d\n,ans);}return 0 ;
} 总结
1.上面这一步就看出 升序排end并且从0递归到n-1的妙处了
2.做题方法先读题并确定需要找出的是什么即以什么变量为中心点此题根据题意你需要找出的是每一步的end都是最小的那个最优解所以对end排序。
因为你每确定出一个ans都能保证此时的end是最小的而start是否满足不用排序出来而是if判断一步就好了啊。所以这题关键不是start而是end最后一段的理解可以看一下上面我给的样例
3.对于sort排序一定要找清楚位置不然很容易犯很低级的错误并且很难查出来
4.if判断啊逻辑关系要找清楚第一个if那里就一直写错了写成了if(node[i].enode[i-1].e)。所以这个if还不如不要反正不影响程序、5.送上 区间完全不覆盖 模板。
核心语句
/* for(i0; in; i){if(node[i].scure){ans;curenode[i].e;}}
*/