集合栈
题目描述
栈是一种数据结构,又被称为后入先出表。现在有一个栈,栈内元素是集合,集合的元素是正整数。
有4种命令
命令 | 命令举例 | 含义 |
push | push (1,2,3) | 将集合(1,2,3)压栈 |
pop | pop | 将栈顶元素弹栈 |
union | union | 将栈顶和次栈顶元素弹出,并将其合并后,压栈 |
intersect | intersect | 将栈顶和次栈顶元素弹出,并将其求交后,压栈 |
输入格式
只有一组测试样例,包含不超过10000条命令。 每条命令占一行,push命令的长度不会超过110个字符,注意push的集合可能为空集,所有集合的元素大小不会超过109。 输入保证所有命令都是合法,能执行的。
输出格式
依次输出每条命令之后,栈顶元素的累加和。如果栈为空,输出“-1”。
样例输入
push ()
pop
push (1,2,3)
push (2,3,4)
intersect
push (5,3)
union
样例输出
0
-1
6
9
5
8
10
vector里嵌套vector非常有意思,这个也是请教了大佬
trtok()和sscanf()的使用,找了很多资料,用于拆分字符串
还有union和intersection方法的使用
和题解不同的是,我没用std::accumulate方法,用了一下测试数据时__int64都爆了,原因未知
就干脆直接遍历了
写的非常冗余,勿喷。。
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
#include <numeric>
using namespace std;
vector<vector<__int64> >ans;
int main(){
char s[200];
int i,j,ids=0;
while(scanf("%s",s)!=EOF){
if(strcmp(s,"push")==0){
vector<__int64> v1;
char ch[15000];
scanf("%s",ch);
char *p=ch;
int flag=1;
while(p){
if(flag==1) {
p = strtok (ch, ",");
}
else p = strtok (NULL, ",");
if(p) {
char str[15000]="";
if(flag==1)
sscanf (p, "%*[(]%100[0-9]", str);//这里%*[(]可以忽略第一个(
else sscanf (p, "%100[0-9]", str);
if(strcmp(str,"")==0) { //对于空集,置0处理
v1.push_back(0);
break;
}
__int64 sum=0;
for(i=0;str[i]!='\0';i++){ //数字字符串转数字
sum+=str[i]-48;
sum=sum*10;
}
sum=sum/10;
v1.push_back(sum);
}
flag=0;
}
std::sort(v1.begin(), v1.end());//一定要排序,否则后面的union,intersect都用不了
ans.push_back(v1);
vector<vector<__int64> >::iterator it=ans.end()-1;
__int64 sum1=0; //求和
for(vector<__int64>::iterator vif=(*it).begin();vif!=(*it).end()&&(*vif!=0);vif++){
sum1+=*vif;
}
printf("%I64d\n",sum1);
}
else if(strcmp(s,"pop")==0){
if(ans.empty()){ //判空
printf("-1\n");
continue;
}
else{
ans.pop_back();
if(ans.empty()){//判空
printf("-1\n");
continue;
}
vector<vector<__int64> >::iterator iet=ans.end()-1;
__int64 sum1=0;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
sum1+=*vif;
}
printf("%I64d\n",sum1);
}
}
else if(strcmp(s,"union")==0){
vector<__int64> vtarget;//union后集合
vector<vector<__int64> >::iterator it=ans.end()-1; //栈顶
vector<vector<__int64> >::iterator itr=ans.end()-2; //次栈
vector<__int64>::iterator vit=(*it).begin();
vector<__int64>::iterator vitr=(*itr).begin();
vtarget.resize((*it).size()+ (*itr).size());//使用union一定要先分配空间
if(*vit==0){ //栈顶为空
ans.pop_back();
vector<vector<__int64> >::iterator iet=ans.end()-1;
__int64 sum1=0;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
sum1+=*vif;
}
printf("%I64d\n",sum1);
continue;
}
else if(*vitr==0){ //次栈为空
vtarget.clear();
vector<vector<__int64> >::iterator iet=ans.end()-1;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
if(*vif!=0) vtarget.push_back(*vif);//可能有0元素,排除0元素后压栈
}
ans.pop_back();
ans.pop_back();
ans.push_back(vtarget);
__int64 sum=0;
iet=ans.end()-1;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
sum+=*vif;
}
printf("%I64d\n",sum);
continue;
}
set_union((*it).begin(), (*it).end(), (*itr).begin(), (*itr).end(), vtarget.begin());
ans.pop_back();
ans.pop_back();
if(vtarget.begin()==vtarget.end()){ //判空
vtarget.push_back(0);
}
ans.push_back(vtarget);
__int64 sum1=0;
vector<vector<__int64> >::iterator iet=ans.end()-1;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
sum1+=*vif;
}
printf("%I64d\n",sum1);
}
else if(strcmp(s,"intersect")==0){
vector<__int64> vtarget;
vector<vector<__int64> >::iterator it=ans.end()-1; //栈顶
vector<vector<__int64> >::iterator itr=ans.end()-2; //次栈顶
vector<__int64>::iterator vit=(*it).begin();
vector<__int64>::iterator vitr=(*itr).begin();
vtarget.resize(min((*it).size(),(*itr).size()));//使用intersect也要分配空间
if(*vit==0||*vitr==0){ //任意一栈为空
vtarget.push_back(0);
ans.pop_back();
ans.pop_back();
ans.push_back(vtarget);
printf("0\n");
continue;
}
set_intersection((*it).begin(), (*it).end(), (*itr).begin(), (*itr).end(), vtarget.begin());
if(vtarget.begin()==vtarget.end()){ //交集为空
vtarget.push_back(0);
}
ans.pop_back();
ans.pop_back();
ans.push_back(vtarget);
vector<vector<__int64> >::iterator iet=ans.end()-1;
__int64 sum1=0;
for(vector<__int64>::iterator vif=(*iet).begin();vif!=(*iet).end();vif++){
sum1+=*vif;
}
printf("%I64d\n",sum1);
}
}
}
大佬,带带我
题目描述
Eric决定在队里实行老队员带新队员的训练制度。Eric给队里的每个人都评估了一个能力值,如果A的能力值高于B的,那么A就可以带B。 但是每个人的都有自己的个性,可能会不喜欢某人,这样必然会影响训练的效果。所以,Eric要大家发邮件给他,告知不喜欢带哪些人,或者不喜欢被哪些人带。
现在,Eric给你一个任务,请计算一下,每个人能带的人的数量。
输入
只有一组样例,第一行是两个整数n(1≤n≤10000),m(0≤m≤n),分别表示队员的数量和收到的邮件数量。 第二行是n个整数,a1,a2,…,an,1≤ai≤109) 依次表示队员的能力值。 以后的m行,每行表示一个队员的邮件,第一个是一个整数i(1≤i≤n),表示第i个队员,第二个是一个整数k(1≤k≤n−1),表示他不喜欢的人的数量,以后的k个整数b1,b2,…,bk,表示不喜欢人的编号。
输入数据保证所有的邮件的发件人都是唯一的,其不喜欢人列表中也没有重复元素,也不会包含自己。 ∑mi=1ki≤106 , ki表示第i份邮件中不喜欢人的数量。
输出
输出一行,n个整数,为每个人能带的人的数量,之间用一个空格隔开,行尾无空格。
样例输入
5 3 10 3 10 4 15 1 1 2 5 3 1 2 3 4 1 5
样例输出
1 0 2 1 0
样例解释
1号,按能力值可以带2和4号,但是他不喜欢2号,所以只能带4号1个人。 2号,能力值最低,不能带任何人,所以是0个。 3号,按能力值可以带2和4号,他没有不喜欢谁,2和4号也都没有不喜欢他,所以他可以带2个人。 4号,按能力值可以带2号,两者没有不喜欢关系,所以4号可以带1个。 5号,按能力可以带1,2,3,4号,但是他不喜欢1,2,3号,4号又不喜欢他,所以他不能带任何人。
提示
巨大的输入量,请使用快读技术
写到快自闭的一题,差点被恶心坏了
用了二维vector容器
最奇怪的点,一开始我是使用c++做的,一直wr,找半天没找到问题
最后,神奇的来了,把所有cin,cout换成c的printf,scanf结果就和标准一样了。。。。。
我怀疑是输入输出太大,c++读入有点问题
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
struct student{
int id;
__int64 power;
int people;
}stu[10003];
struct student2{
int id;
__int64 power;
// int people;
}stu2[10003];
bool cmp_power(student2 x,student2 y){
return x.power < y.power;
}
vector<int>ans[10001];//二维数组表示不喜欢的人
int main(){
// ios::sync_with_stdio(false);//加快cin,cout的速度
int n,m,i,j;
// __int64 power1[10003];
__int64 t;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
stu[i].id=i;
stu2[i].id=i;
scanf("%I64d",&t);
stu[i].power=t;
stu2[i].power=t;
// power1[i]=t;
}
sort(stu2,stu2+n+1,cmp_power);//降序排能力值大小
j=1;
for(i=1;i<=n;i++){//计算没有不喜欢人时候可以带的人数
if(stu2[i].power==stu2[i-1].power&&i!=1) stu[stu2[i].id].people=j-1;
else {
stu[stu2[i].id].people=i-1;
j=i;
}
}
for(int i=0;i<m;i++){ //记录每个不喜欢,并且相互保存
int nums,ids;
scanf("%d%d",&ids,&nums);
for(int j=0;j<nums;j++){
int dislike;
scanf("%d",&dislike);
ans[ids].push_back(dislike);
ans[dislike].push_back(ids);
}
}
for(i=1;i<=n;i++){ //使用unique去重
sort(ans[i].begin(),ans[i].end());
vector<int>::iterator it_1 = ans[i].begin();
vector<int>::iterator it_2 = ans[i].end();
vector<int>::iterator new_end;
new_end = unique(it_1,it_2);
ans[i].erase(new_end,it_2);
}
for(i=1;i<=n;i++){ //遍历vertor容器
for(vector<int>::iterator it=ans[i].begin();it!=ans[i].end();it++){
t=*it;
if(stu[i].power>stu[t].power) { //减去能力强的那位同学可以带的人数
stu[i].people--;
}
}
}
for(i=1;i<=n;i++){
if(i==1)printf("%d",stu[i].people);
else printf(" %d",stu[i].people);
}
printf("\n");
return 0;
}
练习
题目描述
程序设计实践会布置3次练习,练习的有效题目直接关系到同学们的考试资格。
其判定规则如下:
- 第一次考试资格:专题练习一中有效题数达到或超过10题的同学。
- 第二次考试资格:专题练习二中有效题数达到或超过10题的同学。
- 期末考试资格:专题练习三中有效题数达到或超过5题且三个专题有效题数达到或超过30题的同学。
现在给你每个同学的三次练习的有效题数,请计算所有同学的总题数排名和考试资格获得的情况。
输入格式
只有一组样例。
样例的每一行是一个学生的信息,包括学号,姓名,班级,三次练习的有效题数。学生人数不会超过400人。
学号为4位的数字串,姓名为不超过10个字符的英文字母串,班级为不超过4个字母的英文字母和数字组合串。 三次练习的有效题数为正整数,且不超过20。
输出格式
每行输出一个学生的信息,依次为排名,班内排名,学号,姓名,班级,总有效题数,三次练习的有效题数,考试资格。
其中排名按总有效题数逆序排列,排名并列时按学号字典序进行输出。
存在排名并列时,后面紧接着的排名会跳过,比如有两个并列第4,那么后面紧接着的排名为6,而不是5。
考试资格为三位的“01”串,依次表示三场考试的考试资格,“0”表示没有获得考试资格,“1”表示获得考试资格。
所有数据之间有一个空格隔开,行尾无多余空格。
样例输入
6501 Eric CS01 20 20 20
6502 Amber CS01 20 18 10
6503 Peter CS01 20 20 18
6504 Bret CS02 9 20 5
6505 Yang CS02 10 20 4
6506 Kate CS02 20 18 20
样例输出
1 1 6501 Eric CS01 60 20 20 20 111
2 2 6503 Peter CS01 58 20 20 18 111
2 1 6506 Kate CS02 58 20 18 20 111
4 3 6502 Amber CS01 48 20 18 10 111
5 2 6504 Bret CS02 34 9 20 5 011
5 2 6505 Yang CS02 34 10 20 4 110
ctrl加z是输入结束符,也就是EOF
对于多类型的数据输入,用结构体非常合适
strcmp()比较字符串函数 strcpy()复制赋值字符串函数的使用
看清题目的陷阱,题目说输入四位数字学号,样例给的6501啥的,但他测试时用的0016,这样的输入,导致如果用整型数组存的话,输出会变成16,不满四位,直接wr,卡了我好久
输出前置0的数字,可以用%0Xd,其中X为数字,代表输出数字的位数,不足位数则前置补0;
#include <stdio.h>
#include <string.h>
struct student{
int xh;
char name[12];
char class1[12];
int t1,t2,t3,tsum,zg1,zg2,zg3,bp;
}a[500];
int main(){
int i=0,j,k,m,u;
char s;
while(scanf("%d",&a[i].xh)!=EOF)
{
scanf("%s",a[i].name);
scanf("%s",a[i].class1);
scanf("%d",&a[i].t1);
scanf("%d",&a[i].t2);
scanf("%d",&a[i].t3);
a[i].zg1=a[i].zg2=a[i].zg3=0,a[i].bp=0;
a[i].tsum=a[i].t1+a[i].t2+a[i].t3;
if(a[i].t1>=10) a[i].zg1=1;
if(a[i].t2>=10) a[i].zg2=1;
if(a[i].t3>=5&&a[i].tsum>=30) a[i].zg3=1;
i++;
}
k=i;
//for(j=0;j<k;j++){
// printf("%d %s %s %d %d %d\n",a[j].xh,a[j].name,a[j].class1,a[j].t1,a[j].t2,a[j].t3);
// }
char str[101];
for(i=0;i<k;i++) // 冒泡排序
{
for(j=0;j<k-i-1;j++)
{
if(a[j].tsum<a[j+1].tsum||(a[j].tsum==a[j+1].tsum&&a[j].xh>a[j+1].xh))
{
m=a[j].tsum;
a[j].tsum=a[j+1].tsum;
a[j+1].tsum=m;
m=a[j].xh;
a[j].xh=a[j+1].xh;
a[j+1].xh=m;
// printf("m=%d\n",m);
m=a[j].t3;
a[j].t3=a[j+1].t3;
a[j+1].t3=m;
m=a[j].t1;
a[j].t1=a[j+1].t1;
a[j+1].t1=m;
m=a[j].t2;
a[j].t2=a[j+1].t2;
a[j+1].t2=m;
m=a[j].zg1;
a[j].zg1=a[j+1].zg1;
a[j+1].zg1=m;
m=a[j].zg2;
a[j].zg2=a[j+1].zg2;
a[j+1].zg2=m;
m=a[j].zg3;
a[j].zg3=a[j+1].zg3;
a[j+1].zg3=m;
strcpy(str,a[j+1].name);
strcpy(a[j+1].name,a[j].name);
strcpy(a[j].name,str) ;
strcpy(str,a[j+1].class1);
strcpy(a[j+1].class1,a[j].class1);
strcpy(a[j].class1,str) ;
}
}
}
// for(j=0;j<k;j++){
// printf("%d %s %s %d %d %d\n",a[j].xh,a[j].name,a[j].class1,a[j].t1,a[j].t2,a[j].t3);
// }
// printf("%d\n",a[1].t3+a[2].t3);
int cnt=1,flag=1,r; //计算班排
a[0].bp=1;
for(j=1;j<k;j++){
flag=1;
cnt=1;
r=1;
for(i=j-1;i>=0;i--){
if(strcmp(a[i].class1,a[j].class1)==0){
cnt++;
if(a[i].tsum==a[j].tsum) {
a[j].bp=a[i].bp;
r=0;
}
flag=0;
}
}
if(r==1)a[j].bp=cnt;
if(flag==1) a[j].bp=1;
}
m=1;
for(j=0;j<k;j++){ //计算全排
if(a[j].tsum==a[j-1].tsum&&j!=0) printf("%d ",m);
else {
printf("%d ",j+1);
m=j+1;
}
printf("%d %04d %s %s %d %d %d %d %d%d%d\n",a[j].bp,a[j].xh,a[j].name,a[j].class1,a[j].tsum,a[j].t1,a[j].t2,a[j].t3,a[j].zg1,a[j].zg2,a[j].zg3);
}
}
轨迹
题目描述
一个机器人会接收行动的指令,请绘制它的移动轨迹。 使用_ 表示横线,| 表示竖线,要求图形的每行行尾无多余的空格。
注意!!! 如果同一格有横竖两种轨迹,画竖线。
指令格式为 d n,表示按方向d移动n步。方向为LRUD,依次为左右上下。
比如依次执行R 2, U 3, L 5, D 7, R 11五条指令时,轨迹图如下:
_____
| |
| |
| __|
|
|
|
|___________
输入格式
第一行是一个整数n(1≤n≤10000),表示指令的条数。 以后的n行,每行一条指令。
输出格式
按格式要求输出轨迹图。
题目保证轨迹图的宽与高不会超过600。
样例输入
4
L 1
U 1
R 1
D 1
样例输出
_
|_|
这个题写出素数螺旋的话,改改就出来了
要改的地方有:画笔画完后的位置变化,维护边界变量的处理
值得注意的点就是,画的图可能会交叉,按题意是保留竖线,还有要用getchar()来吸收缓存区的换行符
#include<stdio.h>
#include <string.h>
const int dx[]={1,0,-1,0}; // 右 上 左 下
const int dy[]={0,-1,0,1};
//RULD
const int cy[4][4]=
{
{0,0,0,1},
{0,0,0,1},
{0,0,0,1},
{-1,-1,-1,0}
};
const int cx[4][4]=
{
{0,0,-1,0},
{1,0,-1,0},
{1,0,0,0},
{1,0,-1,0}
};
char out[1205][1205]={' '};
int line,list;
int left,right,top,low;//边界
void gx(int x1,int y1){
list=x1;
line=y1;
}
void draw(int op,int n,int list,int line){
int t=n;
while(t--){
if(op==0){//向右画
if(out[line][list]!='|') out[line][list]='_';
}
if(op==1){//向上画
out[line][list]='|';
}
if(op==2){//向左画
if(out[line][list]!='|') out[line][list]='_';
}
if(op==3){//向下画
out[line][list]='|';
}
list+=dx[op];
line+=dy[op];
// printf("line=%d list=%d\n ",line,list);
}
if(op==0){//向右画
if(list-1>right) right=list-1;
if(line>low) low=line;
if(line<top) top=line;
}
if(op==1){//向上画
if(line+1<top) top=line+1;
if(list>right) right=list;
if(list<left) left=list;
}
if(op==2){//向左画
if(line<top) top=line;
if(line>low) low=line;
if(list+1<left) left=list+1;
}
if(op==3){//向下画
if(line-1>low) low=line-1;
if(list<left) left=list;
if(list>right) right=list;
}
gx(list,line);
}
int main() {
int k,T,n;
int i,j,flag;
int a,b;
int op,bfop;
char ch;
list=600;
line=600;
left=600,right=600,top=600,low=600;
flag=1;
memset(out,' ',sizeof(out));
scanf("%d",&T);
getchar();
while(T--){
scanf("%c%d",&ch,&n);
getchar();
if(ch=='R') op=0;
if(ch=='U') op=1;
if(ch=='L') op=2;
if(ch=='D') op=3;
if(flag==1){
bfop=op;
flag=0;
}
list+=cx[bfop][op];
line+=cy[bfop][op];
draw(op,n,list,line);
bfop=op;
}
for(i=top;i<=low;i++){
for(j=right;j>=left;j--){
if(out[i][j]==' ') out[i][j]='\0';
else{
break;
}
}
}
for(i=top;i<=low;i++){
for(j=left;j<=right&&out[i][j]!='\0';j++){
printf("%c",out[i][j]);
}
printf("\n");
}
return 0;
}
礼物
题目描述
马上要“六一”儿童节了,女儿吵着让爸爸买礼物。可女儿要买的东西实在太多了,爸爸手头上只有M元钱,觉得可能不能全部满足她,但是他又希望女儿尽量开开心心的。爸爸看了女儿的礼物单,上面有N件礼物,查到了所有礼物的价格,以及买给她会女儿开心度增加的值和不买给她开心度减少的值(每种礼物只能买1个)。他想知道开心度最大是多少,希望你能帮帮他。
输入
存在多组测试数据
每组数据的第一行是两个整数N(1 ≤ N ≤ 16),M(1 ≤ M ≤ 1,000)。如果N和M为0,表示输入结束。
以后的N行,每行为一个礼物的价格P(1 ≤ P ≤ 200),买增加的开心度I(1 ≤ I ≤ 50),不买减少的开心度D(1 ≤ D ≤ 50)。
输出
每个样例输出1行,为最大的开心度。
样例输入
3 100 30 10 5 80 20 16 60 15 7 3 100 30 10 5 70 20 16 60 15 6 0 0
样例输出
9 24
会用二进制来枚举子集
这题要注意的点就是max的值是可以小于0的,一开始我把他初始化为0,wr了几次
#include <stdio.h>
#include <string.h>
int main(){
int N,M,t,i,j,P,I,D;
int a[20],b[20],c[20];
scanf("%d%d",&N,&M);
while(N!=0||M!=0){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
t=N;
i=0;
while(t--){
scanf("%d%d%d",&P,&I,&D);
a[i]=P; //价格
b[i]=I;//满意度
c[i]=D;//不满
i++;
}
int sum=0,happy=0,max=-9999999;
for( i = 0;i < 1<<N;i ++){
sum=0,happy=0;
for( j = 0;j < N;j ++) //遍历某个 十进制数的 所有二进制的每一位
{
if(i & 1<<j) //检查二进制数的某一位 是否为 1,也就是第几个礼物被买
{
// printf("1");
sum+=a[j];
happy+= b[j];
}
else happy=happy-c[j];
// printf("0");
}
if(sum<=M){
if(happy>=max) max=happy;
}
}
printf("%d\n",max);
scanf("%d%d",&N,&M);
}
}