cin--空格和回车键表示输入结束
gets()---回车键表示结束
int main(){
char str[90];
gets(str); //回车表示输入结束
long len=strlen(str);
long r=0,h=0;
char ans[90][90];
for(long i=0;i<len;i++){
if(str[i]!=' ')
{
ans[r][h++]=str[i];
}
else{
ans[r][h]='\0';
r++;
h=0;
}
}
for(long j=r;j>=0;j--){
printf("%s",ans[j]);
if(j>0) printf(" ");
}
return 0;
}
比较函数cmp(基本数据类型、结构体类型、STL容器进行自定义规则排序时的写法)
--基本数据类型:int double char --
#include<cstdio>
#include <algorithm>
using namespace std;
bool cmp(int a,int b){
return a>b;
}
int main(){
int a[5]={3,1,4,2};
sort(a,a+4,cmp);
for(int i=0;i<4;i++)
printf("%d",a[i]);
return 0;
}
----结构体类型
bool cmp(node a,node b){
if(a.x!=b.x) return a.x>b.x;
else return a.y<b.y;
}
---容器的排序
在STL容器中,只有vector,string,deque是可以使用sort的。 map,set这种容器元素本身有序,是通过红黑树实现的。
#include<cstdio>
const int maxn=100;
char s[maxn][5],temp[5];
int hashtable[26*26*26+10];//全局变量自动初始化为0
int hasnfunc(char s[],int len){
int id=0;
for(int i=0;i<len;i++){
id=id*26+(s[i]-'A');
}
return id;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%s",s[i]);
int id=hasnfunc(s[i], 3);
hashtable[id]++;
}
for(int i=0;i<m;i++){
scanf("%s",temp);
int id=hasnfunc(temp, 3);
printf("%d",hashtable[id]);
}
return 0;
}
#include<cstdio>
const int maxn=11;
//p为当前排列,hastable记录当前的x是否已经在p中
int n,p[maxn],hastable[maxn]={false};
void generatep(int index){
if(index==n+1){ //递归边界,以及处理完排列的1~n位
for(int i=1;i<=n;i++){
printf("%d",p[i]);
}
printf("\n");
return;
}
for(int x=1;x<=n;x++){ //枚举1~n,试图将x填入p[index]
if(hastable[x]==false){
p[index]=x;
hastable[x]=true;
generatep(index+1);
hastable[x]=false; //已经处理完p[index]为x的子问题,还原状态
}
}
}
int main(){
n=3;
generatep(1);
return 0;
}
----n皇后问题----------
#include<cstdio>
#include <cmath>
const int maxn=11;
//p为当前排列,hastable记录当前的x是否已经在p中
int n,p[maxn],hastable[maxn]={false};
int count=0;
void generatep(int index){
if(index==n+1){ //递归边界,以及处理完排列的1~n位
count++;
return;
}
for(int x=1;x<=n;x++){ //枚举1~n,试图将x填入p[index]
if(hastable[x]==false){
bool flag=true; //表示当前皇后不会和之前的皇后冲突
for(int pre=1;pre<index;pre++){
if(fabs((index-pre)) == fabs(x-p[pre])){
flag=false;
break;
}
}
if(flag)
{
p[index]=x;
hastable[x]=true;
generatep(index+1);
hastable[x]=false; //已经处理完p[index]为x的子问题,还原状态
}
}
}
}
int main(){
n=6;
generatep(1);
printf("%d",count);
printf("\n");
return 0;
}
----//算法笔记120页--
--月饼---
#include<cstdio>
#include <algorithm>
using namespace std;
struct mooncake{
double store; //库存量
double sell; //总售价
double price; //月饼单价
}cake[1010];
bool cmp(mooncake a,mooncake b){
return a.price>b.price;
}
int main(){
int n; //月饼的种类
double d;//最大需求量
scanf("%d %lf",&n,&d);
for(int i=0;i<n;i++){
scanf("%lf",&cake[i].store);
}
for(int i=0;i<n;i++){
scanf("%lf",&cake[i].sell);
cake[i].price=cake[i].sell/cake[i].store;
}
sort(cake,cake+n,cmp);
double ans=0;
for(int i=0;i<n;i++){
if(cake[i].store<d){
d-=cake[i].store;
ans+=cake[i].sell;
}
else{
ans+=cake[i].price*d;
break;
}
}
printf("%.2f",ans);
printf("\n");
return 0;
}
int randparttion(int A[],int left,int right){
//生成[left,right]内的随机数p round()四舍五入-math.h文件里面 RAND_MAX是stdlib.h中的一个常数
int p=(round(1.0*rand()/RAND_MAX*(right-left)+left));
swap(A[p],A[left]);
int temp=A[left];
while(left<right){
while(left<right && temp<A[right] )
right--;
A[left]=A[right];
while(left<right && temp>=A[left])
left++;
A[right]=A[left];
}
A[left]=temp;
return left;
}
void quicksort(int A[],int left,int right){
if(left<right){
int p=randparttion(A, left, right);
quicksort(A, left, p-1);
quicksort(A, p+1, right);
}
}
思想:
#include <iostream>
#include <cstring>
using namespace std;
//int 所占字节数:4 最大值:2147483647 最小值:-2147483648
const int maxn=100010;
const int mod=1000000007;
char str[maxn];
int leftnump[maxn]={0}; //记录每一位左边P的个数(包括当前位)
int main(){
gets(str); //gets(str) 以enter键结束
int len=strlen(str);
for(int i=0;i<len;i++){
if(i>0){
leftnump[i]=leftnump[i-1];
}
if(str[i]=='P')
leftnump[i]++;
}
//rightnumt记录当前累计右边T的个数
int ans=0,rightnumt=0;
for(int j=len-1;j>=0;j--){
if(str[j]=='T')
rightnumt++;
else if(str[j]=='A')
ans=(ans+leftnump[j]*rightnumt)%mod;
}
cout<<ans<<'\n';
return 0;
}
从一个无序数组中,选择第k大的数,采用随机选择算法,对任何的输入都可以达到o(n)的期望复杂度,最坏时间复杂度是o(n*n)
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <cmath>
using namespace std;
int randparttion(int A[],int left,int right){
//生成[left,right]内的随机数p round()四舍五入-math.h文件里面 RAND_MAX是stdlib.h中的一个常数
int p=(round(1.0*rand()/RAND_MAX*(right-left)+left));
swap(A[p],A[left]);
int temp=A[left];
while(left<right){
while(left<right && temp<A[right] )
right--;
A[left]=A[right];
while(left<right && temp>=A[left])
left++;
A[right]=A[left];
}
A[left]=temp;
return left;
}
//找无序数组中d第k大的数
int randselect(int A[],int left,int right,int k){
if(left==right) return A[left]; //边界
//划分后主元位置为A[p]
int p=randparttion(A, left, right);
int m=p-left+1; //A[p]是A[left,right]中的第m大的数
if(m==k) return A[p];
if(k<m) { return randselect(A, left, p-1, k);}
else
{
return randselect(A, p+1, right, k-m);
}
}
int main(){
int randselect(int A[],int left,int right,int k);
srand((unsigned)time(NULL));
int array[100010];
int num;
int n=0;
do{
cin>>num;
array[n++]=num;
}while(getchar()!='\n');
int k;
cin>>k;
int val=randselect(array, 0, n-1, k);
cout<<val<<'\n';
return 0;
}
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
bool cmp(int a,int b)
{
return a>b;
}
void to_array(int n,int num[]){ //将n的每一位存到数组中
for(int i=0;i<4;i++){
num[i]=n%10; //每次把最后一个数字取出来
n=n/10;
}
}
int to_number(int num[]){
int sum=0;
for(int i=0;i<4;i++)
sum=sum*10+num[i];
return sum;
}
int main(){
int n,maxn,minn;
cin>>n;
int num[5];
while(1){
to_array(n, num);
sort(num,num+4);
minn=to_number(num);
sort(num,num+4,cmp);
maxn=to_number(num);
n=maxn-minn;
cout<<maxn<<"-"<<minn<<"="<<n<<'\n';
if(n==0 || n==6174) break;
}
return 0;
}
-------自己做的------------
#include <iostream>
#include <cmath>
using namespace std;
const int kaprekar=6174;
int numheidong(int num){
int a[4];
for(int i=1;i<4;i++){
a[i-1]=num/pow(10,4-i);
num=num-a[i-1]*pow(10,4-i);
}
a[3]=num%10;
int t1,t2;
for(int i=1;i<4;i++){
int temp=a[i];
int j=i-1;
while(j>=0 && a[j]<temp){
a[j+1]=a[j];
j--;
}
a[j+1]=temp;
}
t1=a[0]*1000+a[1]*100+a[2]*10+a[3];
t2=a[3]*1000+a[2]*100+a[1]*10+a[0];
num=t1-t2;
cout<<t1<<"-"<<t2<<"="<<num<<'\n';
return num;
}
int main(){
int num;
cin>>num;
int p=numheidong(num);
while(p!=kaprekar){
p=numheidong(p);
}
return 0;
}
最小公倍数在最大公约数d的基础上,为ab/d,防止ab溢出,写为a/d*b;
#include <iostream>
using namespace std;
int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
int lcm(int a,int b){
int num=gcd(a, b);
num=a/num*b;
return num;
}
int main(){
int n,m;
while(cin>>n>>m){
cout<<gcd(n,m)<<" "<<lcm(n,m);
}
return 0;
}
#include <iostream>
using namespace std;
int gcd(int a,int b){
if(b==0) return a;
else return gcd(b,a%b);
}
/*
分数的制定需满足三项规则:
1.使down为非负数。如果分数为负数,则令分子为负数;
2.如果该分数恰好为0,则令down=1;
3.分子和分母没有除了1之外的公约数
*/
struct Fraction{
int up,down;
};
//分数的化简:约分,且满足三项规则
Fraction reduction(Fraction result){
if(result.down<0){
result.up=-result.up;
result.down=-result.down;
}
if(result.up==0){
result.down=1;
}
else{
int d=gcd(abs(result.up),abs(result.down));
result.up=result.up/d;
result.down=result.down/d;
}
return result;
}
Fraction add(Fraction f1,Fraction f2){
Fraction result;
result.up=f1.up*f2.down+f2.up*f1.down;
result.down=f1.down*f2.down;
result=reduction(result);
return result;
}
int main(){
Fraction f1;
cin>>f1.up>>f1.down;
f1=reduction(f1);
Fraction f2;
cin>>f2.up>>f2.down;
f2=reduction(f2);
Fraction f=add(f1, f2);
if(f.down==1)
cout<<f.up<<'\n';
else
cout<<f.up<<"/"<<f.down<<'\n';
return 0;
}
bool isPrime(int n){
if(n<=1) return false;
int sqr=(int)sqrt(1.0*n);
for(int i=2;i<=sqr;i++){
if(n%i==0)
return false;
}
return true;
}
-------筛法----------
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=101; //表长
int prime[maxn]; //prime数组存放所有素数,pnum存放素数个数
int pnum=0;
bool p[maxn]={0}; //如果i为素数,则p[i]为false;否则为p[i]为true
void Find_prime(){
for(int i=2;i<maxn;i++){
if(p[i]==false){
prime[pnum++]=i;
for(int j=i+i;j<maxn;j+=i){
p[j]=true;
}
}
}
}
int main(){
Find_prime();
for(int i=0;i<pnum;i++){
cout<<prime[i]<<" ";
}
return 0;
}
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=100001; //表长
int prime[maxn]; //prime数组存放所有素数,pnum存放素数个数
int pnum=0;
bool p[maxn]={0}; //如果i为素数,则p[i]为false;否则为p[i]为true
void Find_prime(int n){
for(int i=2;i<maxn;i++){
if(p[i]==false){
prime[pnum++]=i;
if(pnum>=n) break; //控制素数个数
for(int j=i+i;j<maxn;j+=i){
p[j]=true;
}
}
}
}
int main(){
int m,n;
cin>>m>>n;
Find_prime(n);
int count=0;
for(int i=m-1;i<n;i++){
count++;
cout<<prime[i];
if(count%10!=0)
cout<<" ";
else
cout<<'\n';
}
cout<<'\n';
return 0;
}
前提:得到素数表
#include <iostream>
#include <cmath>
using namespace std;
const int maxn=10001;
int prime[maxn];
int pnum=0;
bool is_prime(int n){
if(n==1) return false;
int sqr=(int)sqrt(1.0*n);
for(int i=2;i<=sqr;i++){
if(n%i!=0) return false;
}
return true;
}
void Find_prime() //求素数表
{
for(int i=1;i<maxn;i++)
{
if(is_prime(i)==true)
prime[pnum++]=i;
}
}
struct factor{
int x,cnt; //x是质因子,cnt是它的个数
}fac[10];
int main(){
int n,num=0;//num为n的不同质因子的个数
cin>>n;
Find_prime();
if(n==1) cout<<"1=1"<<'\n';
else{
cout<<n<<"=";
int sqr=(int)sqrt(1.0*n);
for(int i=0;i<pnum && prime[i]<=sqr;i++){
if(n%prime[i]==0){
fac[num].x=prime[i];
fac[num].cnt=0; //记录该因子
while(n%prime[i]==0){ //计算质因子prime[i]的个数
fac[num].cnt++;
n/=prime[i];
}
num++;
}
if(n==1) break;//及时推出循环,节省时间
}
//如果无法被sqr以内的质因子除尽,那么一定有一个大于sqr的质因子,即为除了剩下的n
if(n!=1){
fac[num].x=n;
fac[num++].cnt=1;
}
for(int i=0;i<num;i++){
if(i>0) cout<<"*";
cout<<fac[i].x;
if(fac[i].cnt>1)
cout<<"^"<<fac[i].cnt;
}
}
cout<<'\n';
return 0;
}
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
struct bign{
int d[1000];
int len;
bign(){
memset(d,0,sizeof(d));
len=0;
}
};
bign change(char str[]){
bign a;
a.len=strlen(str);
for(int i=0;i<a.len;i++){
a.d[i]=str[a.len-1-i]-'0';
}
return a;
}
int compare(bign a,bign b){//比较ab的大小,a大:1,ab相等:0,a小:-1
if(a.len>b.len) return 1;
else if(a.len<b.len) return -1;
else {
for(int i=a.len-1;i>=0;i--){
if(a.d[i]>b.d[i]) return 1;
else if(a.d[i]<b.d[i]) return -1;
}
return 0;
}
}
bign add(bign a,bign b){//高精度a+b
bign c;
int carry=0; //carry是进位
for(int i=0;i<a.len || i<b.len;i++){//以较长的为界限
int temp=a.d[i]+b.d[i]+carry;
c.d[c.len++]=temp%10;
carry=temp/10;
}
if(carry!=0)
c.d[c.len++]=carry;
return c;
}
//使用sub函数前需要比较两个数的大小,如果被减数小于减数,需要交换两个变量的位置,输出负号,再使用sub函数
void show(bign a){
for(int i=a.len-1;i>=0;i--){
cout<<a.d[i];
}
}
bign sub(bign a,bign b){
bign c;
for(int i=0;i<a.len || i<b.len;i++){
if(a.d[i]<b.d[i]){
a.d[i+1]--;
a.d[i]+=10;
}
c.d[c.len++]=a.d[i]-b.d[i];
}
while(c.len-1>=1 && c.d[c.len-1]==0)
c.len--; //去除高位的0,同时至少保留一位最低位
return c;
}
int main(){
char str1[1000],str2[1000];
cin>>str1>>str2;
bign a=change(str1);
bign b=change(str2);
// show(add(a,b));
show(sub(a,b));
cout<<'\n';
return 0;
}
#include <iostream>
#include<string>
#include <queue>
#include <stack>
#include <map>
using namespace std;
struct node{
double num; //操作数
char op; //操作符
bool flag; //true表示操作数,false表示操作符
};
string str;
stack<node> s; //操作符栈
queue<node> q; //后缀表达式序列
map<char, int> op;
void Change(){ //将中缀表达式转为后缀表达式
node temp;
for(int i=0;i<str.length();){
if(str[i]>='0' && str[i]<='9')
{
temp.flag=true; //标记是数字
temp.num=str[i++]-'0';
while(i<str.length() && str[i]>='0' && str[i]<='9'){
temp.num=temp.num*10+str[i]-'0';
i++;
}
q.push(temp);
}
else{
while(!s.empty() && op[str[i]]<=op[s.top().op]){
q.push(s.top());
s.pop();
}
temp.flag=false;
temp.op=str[i];
s.push(temp);
i++;
}
}
while(!s.empty()){
q.push(s.top());
s.pop();
}
}
double cal(){
double temp1,temp2;
node cur,temp;
while(!q.empty()){
cur=q.front();
q.pop();
if(cur.flag==true) s.push(cur);
else{
temp2=s.top().num;
s.pop();
temp1=s.top().num;
s.pop();
temp.flag=true;
if(cur.op=='+') temp.num=temp1+temp2;
else if(cur.op=='-') temp.num=temp1-temp2;
else if(cur.op=='*') temp.num=temp1*temp2;
else if(cur.op=='/') temp.num=temp1/temp2;
s.push(temp);
}
}
return s.top().num;
}
int main(int argc, const char * argv[]) {
op['+']=op['-']=1;
op['*']=op['/']=2;
while(getline(cin,str),str!="0"){
for(string::iterator it=str.end();it!=str.begin();it--){
if(*it==' ') str.erase(it); //把表达式中的空格都擦掉
}
while(!s.empty()) s.pop(); //初始化栈
Change();
cout<<cal()<<'\n';
}
return 0;
}
背包问题:有n件物品,每件物品重量为w[i],价值为c[i].现在需要选出若干物品放入一个容器为V的背包中,使得在选入背包的物品重量和不超过容量v的前提下,让背包中物品的价值之和最大,求最大价值。
深度优先搜索:递归实现
#include<iostream>
using namespace std;
const int maxn=30;
int n,V,maxValue=0;
int w[maxn],c[maxn];
void DFS(int index,int sumW,int sumC){
if(index==n){
if(sumW<=V && maxValue<sumC){
maxValue=sumC;
}
return;
}
DFS(index+1, sumW, sumC);
DFS(index+1, sumW+w[index], sumC+c[index]);
}
int main(){
cin>>n>>V;
for(int i=0;i<n;i++){
cin>>w[i];
}
for(int i=0;i<n;i++){
cin>>c[i];
}
DFS(0, 0, 0);
cout<<maxValue<<'\n';
return 0;
}
广度优先搜索:队列实现
给出一个n*m的矩阵,矩阵中的元素为0或1。称位置(x,y)与其上下左右四个位置(x,y+1),(x,y-1),(x+1,y),(x-1,y)是相邻的。如果矩阵中有若干个1是相邻的(不必两两相邻),那么称这些1构成了一个"块"。求给定的矩阵中"块"的个数。
#include<iostream>
#include <queue>
using namespace std;
const int maxn=100;
struct node{
int x,y;
}Node;
int n,m;
int matrix[maxn][maxn];
bool inq[maxn][maxn]={false}; //记录是否入队
int X[4]={0,0,1,-1};
int Y[4]={1,-1,0,0};
bool judge(int x,int y){ //判断该元素是否越界
if(x>=n || x<0 || y>=m || y<0)
return false;
if(matrix[x][y]==0 || inq[x][y]==true) return false;
return true;
}
void BFS(int x,int y){
queue<node> q;
Node.x=x;
Node.y=y;
q.push(Node);
inq[x][y]=true;
while(!q.empty()){
node top=q.front();
q.pop();
for(int i=0;i<4;i++){
int newx=top.x+X[i];
int newy=top.y+Y[i];
if(judge(newx,newy)){
Node.x=newx;
Node.y=newy;
q.push(Node);
inq[newx][newy]=true;
}
}
}
}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cin>>matrix[i][j];
}
int ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(matrix[i][j]==1 && inq[i][j]==false){
ans++;
BFS(i, j);
}
}
}
cout<<ans<<'\n';
return 0;
}
二叉树:链表存储
中序序列可以与先序序列、后序序列、层次序列中的任意一个序列来构建一个二叉树,二后三者两两搭配或是三个一起上都无法构建唯一的二叉树。原因是先序、后序、层序均是提供根结点,作用是相同的,都必须由中序序列来区分左右子树。
//已知中序、后序 求层序
#include<iostream>
#include <queue>
#include <vector>
using namespace std;
vector<int> postorder;
vector<int> inorder;
struct node{
int data;
node* lchild;
node* rchild;
node(int d):data(d),lchild(NULL),rchild(NULL){};
};
node* createleveltree(int posl,int posr,int inl,int inr){
if(posr<posl)
return NULL;
node* nownode=new node(postorder[posr]);
int k;
for(k=inl;k<=inr;k++){
if(inorder[k]==postorder[posr])
break;
}
int numlen=k-inl;
nownode->lchild=createleveltree(posl, posl+numlen-1, inl, k-1);
nownode->rchild=createleveltree(posl+numlen, posr-1, k+1, inr);
return nownode;
}
int main(){
int n;
cin>>n;
int temp;
for(int i=0;i<n;i++){
cin>>temp;
postorder.push_back(temp); //向vector里面加数据用push_back(value)函数,vector[i]适合访问数据
}
for(int i=0;i<n;i++){
cin>>temp;
inorder.push_back(temp);
}
queue<node*> inq; //队列存放的是地址
node* rootnode=createleveltree(0, n-1, 0, n-1);
inq.push(rootnode);
while(!inq.empty()){
node nod=*inq.front();
cout<<nod.data<<" ";
if(nod.lchild!=NULL) inq.push(nod.lchild);
if(nod.rchild!=NULL) inq.push(nod.rchild);
inq.pop();
}
cout<<endl;
return 0;
}
#include<iostream>
#include <queue>
using namespace std;
const int maxn=30;
int inpos=0;
/*struct 结构体类型名
{
类型名 成员名;
类型名 成员名;
……
};
先声明结构体类型,再定义结构体变量名
声明结构体类型,不分配空间
定义结构体类型变量,就要分配内存空间*/
struct node{
int data;
int lchild;
int rchild;
}Node[maxn];
int newnode(int v){
Node[inpos].data=v;
Node[inpos].lchild=-1;
Node[inpos].rchild=-1;
return inpos++;
}//创建新的结点
void search(int root,int x,int newdata){
if(root==-1)
return;
if(Node[root].data==x)
Node[root].data=newdata;
search( Node[root].lchild, x, newdata); //往左子树搜索
search( Node[root].rchild, x, newdata);
}
void insert(int &root,int x){
if(root==-1){ //当插入的是空树时
root=newnode(x);
return;
}
if(Node[root].lchild==-1)
insert(Node[root].lchild, x);
else
insert(Node[root].rchild, x);
}
int create(int data[],int n){
int root=-1;
for(int i=0;i<n;i++){
insert(root, data[i]);
}
return root;
}
//先序遍历
void preorder(int root){
if(root==-1)
return;
cout<<Node[root].data<<" ";
preorder(Node[root].lchild);
preorder(Node[root].rchild);
}
//中序遍历
void inorder(int root){
if(root==-1)
return;
inorder(Node[root].lchild);
cout<<Node[root].data<<" ";
inorder(Node[root].rchild);
}
//后序遍历
void postorder(int root){
if(root==-1)
return;
postorder(Node[root].lchild);
postorder(Node[root].rchild);
cout<<Node[root].data<<" ";
}
//层序遍历
void layerorder(int root){
queue<int> q;
q.push(root);
while(!q.empty()){
int now=q.front();
q.pop();
cout<<Node[now].data<<" ";
if(Node[now].lchild!=-1)
q.push(Node[now].lchild);
if(Node[now].rchild!=-1)
q.push(Node[now].rchild);
}
}
int main(){
int n;
int data[maxn];
cin>>n;
for(int i=0;i<n;i++){
cin>>data[i];
}
int root=create(data, n);
preorder(root);
cout<<'\n';
inorder(root);
cout<<'\n';
postorder(root);
cout<<'\n';
layerorder(root);
cout<<'\n';
cout<<"输入要替换的数据:"<<'\n';
int x,newdata;
cin>>x>>newdata;
search(root,x,newdata);
preorder(root);
return 0;
}
给定一棵树和每个节点的权值,求所有从根结点到叶子结点的路径,使得每条路径上的结点的权值之和等于给定的常数s.如果有多条这样的路径,则按路径非递增顺序输出。
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
const int MAXN=110;
struct node{
int weight;
vector<int> child;
}Node[MAXN];
bool cmp(int a,int b){
return Node[a].weight>Node[b].weight;//按结点域从大到小排序
}
int n,m,s;//结点树、非叶子结点数、给定的和
int path[MAXN];
//当前访问结点为index.numNode为当前路径path上的结点个数
//sum为当前的结点点权和
void DFS(int index,int numNode,int sum){
if(sum>s) return;
if(sum==s){
if(Node[index].child.size()!=0) return; //非叶子结点
//到达叶子结点,此时path[]中存放了一条完整的路径,输出它
for(int i=0;i<numNode;i++)
{
cout<<Node[path[i]].weight;
if(i<numNode-1) cout<<" ";
else cout<<'\n';
}
return;
} for(int i=0;i<Node[index].child.size();i++){
int child=Node[index].child[i];
path[numNode]=child;
DFS(child, numNode+1, sum+Node[child].weight);
}
}
int main(){
cin>>n>>m>>s;
for(int i=0;i<n;i++)
cin>>Node[i].weight;
int id,k,child;
for(int i=0;i<m;i++){
cin>>id>>k;
for(int j=0;j<k;j++){
cin>>child;
Node[i].child.push_back(child);
}
sort(Node[id].child.begin(), Node[id].child.end(), cmp); //排序
}
path[0]=0;
DFS(0, 1, Node[0].weight);
return 0;
}
----------
input:
20 9 24
10 2 4 3 5 10 2 18 9 7 2 2 1 3 12 1 8 6 2 2
0 4 1 2 3 4
2 1 5
4 2 6 7
3 3 11 12 13
6 1 9
7 2 8 10
16 1 15
13 3 14 16 17
17 2 18 19
output:
10 5 2 7
10 4 10
10 3 3 6 2
10 3 3 6 2
Program ended with exit code: 0
两种方式:邻接矩阵和邻接表(可用vector实现)
连通块:连通分量和强连通分量
DFS遍历图的思路:将经过的顶点设置为已访问,在下次递归碰到这个顶点时就不再去处理,直到整个图的顶点都被标记已访问
DFS(u){
vis[u]=true; //设置u已被访问
for(从u出发能到达的所有顶点v){
if(vis[v]==false){
DFS(v); //递归访问v
}
}
}
DFSTrave(G) {//遍历图G
}
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn=2010; //总人数
const int INF=100000000; //无穷大
map<int,string> intToString; //编号->姓名
map<string,int>stringToInt; //姓名->编号
map<string,int>Gang; //head->人数
int G[maxn][maxn]={0},weight[maxn]={0}; //邻接矩阵G,点权weight
int n,k,numperson=0; //边数n,下限k,总人数numperson
bool vis[maxn]={false}; //标记是否被访问
//DFS函数访问单个连通块,nowvisit为当前访问编号
//head为头目,nummember为成员编号,totalvalue为连通块的总边权
void DFS(int nowvisit,int& head,int& nummember,int& totalvalue){
nummember++;//成员人数加1
vis[nowvisit]=true; //标记nowvisit已访问
if(weight[nowvisit]>weight[head]){
head=nowvisit; //当前访问结点的点权大于头目的点权,则更新头目
}
for(int i=0;i<nummember;i++) //枚举所有人
{
if(G[nowvisit][i]>0){//如果从nowvisit能到达v
totalvalue+=G[nowvisit][i];
G[nowvisit][i]=G[i][nowvisit]=0; //删除这条边,防止回头
if(vis[i]==false){ //如果i未被访问,则递归访问i
DFS(i, head, nummember, totalvalue);
}
}
}
}
//遍历整个图,获取每个连通块的信息
void DFSTrave(){
for(int i=0;i<numperson;i++){
if(vis[i]==false){
int head=i,nummember=0,totalvalue=0;//头目、成员数、总边权
DFS(i, head, nummember, totalvalue);
if(nummember>2 && totalvalue>k){
//intToString[head]为头目的字符串姓名
Gang[intToString[head]]=nummember;
}
}
}
}
int change(string str){
if(stringToInt.find(str)!=stringToInt.end()){//如果str已经出现过
return stringToInt[str]; //返回编号
}
else{
stringToInt[str]=numperson; //str的编号为numperson
intToString[numperson]=str;
return numperson++; //总人数加1
}
}
int main(){
int w;
string str1,str2;
//控制台输入s初始信息
cin>>n>>k;
for(int i=0;i<n;i++){
cin>>str1>>str2>>w;
int id1=change(str1);
int id2=change(str2);
weight[id1]+=w;
weight[id2]+=w;
G[id1][id2]+=w;
G[id2][id1]+=w;
}
DFSTrave(); //遍历整个图,获得Gang的信息
cout<<Gang.size()<<'\n';
map<string,int>::iterator it;
for(it=Gang.begin();it!=Gang.end();it++)
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
--复杂度o(n)--
#include<iostream>
#include <algorithm>
using namespace std;
const int maxn=10010;
int A[maxn],dp[maxn]; //状态dp[i]表示以A[i]作为末尾的连续序列的最大和
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>A[i];
}
dp[0]=A[0];
for(int i=1;i<n;i++){
dp[i]=max(A[i], dp[i-1]+A[i]);
}
int k=0;
for(int i=1;i<n;i++){
if(dp[i]>dp[k])
k=i;
}
cout<<dp[k]<<'\n';
return 0;
}
#include
#include
using namespace std;
const int maxn=10010;
int A[maxn],dp[maxn]; //状态dp[i]表示以A[i]作为末尾的连续序列的最大和
int main(){
int n;
cin>>n;
for(int i=0;i>A[i];
}
int ans=-1;
for(int i=0;idp[i]))
dp[i]=dp[j]+1;
}
ans=max(ans,dp[i]);
}
cout<
#include
#include
#include
using namespace std;
const int N=100;
char A[N],B[N];
int dp[N][N];
int main(){
gets(A+1); //从下标1开始读入
gets(B+1);
int lenA=(int)strlen(A+1);
int lenB=(int)strlen(B+1); //由于读入时从1开始读入,读取长度也从1开始
//边界
for(int i=0;i<=lenA;i++)
dp[i][0]=0;
for(int j=0;j
#include<iostream>
#include <string>
using namespace std;
const int maxn=100;
char S[maxn];
int dp[maxn][maxn];//dp[i][j]表示从i到j的字串,如果是回文串,则为1,如果不是,则为0;
int main(){
gets(S);
int len=(int)strlen(S);
int ans=1;
memset(dp, 0, sizeof(dp)); //dp数组初始化为0
//边界,将长度为1或者2的回文串的长度初始化
for(int i=0;i<=len;i++){
dp[i][i]=1;
if(S[i]==S[i+1] && i<len-1)
{ dp[i][i+1]=1;
ans=2;//初始化时注意当前最长的回文子串
}
}
//状态转移方程
for(int L=3;L<=len;L++){ // L为子串的长度
for(int i=0;i+L-1<len;i++){ //枚举子串的起始端点
int j=i+L-1; //子串的右端点
if(dp[i+1][j-1]==1 && S[i]==S[j])
{
dp[i][j]=1;
ans=L; //更新最长回文子串
}
}
}
cout<<ans<<'\n';
return 0;
}
复杂度:o(nV)
--dp[i][v]表示的是恰好为v的情况,所以要枚举dp[n][v](0<=v<=V),取其最大值才是最后的结果 时间复杂度为O(nV)--
#include<iostream>
#include <algorithm>
using namespace std;
const int maxn=100;
const int maxv=1000;
int w[maxn],c[maxn],dp[maxv];
int main(){
int n,V;
cin>>n>>V;
for(int i=1;i<=n;i++)
cin>>w[i];
for(int i=1;i<=n;i++)
cin>>c[i];
//边界
for(int v=0;v<=V;v++){
dp[v]=0;
}
for(int i=1;i<=n;i++){
for(int v=V;v>=w[i];v--){
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
}
}
int maxvalue=0;
for(int v=0;v<=V;v++){
if(dp[v]>maxvalue)
maxvalue=dp[v];
}
cout<<maxvalue<<'\n';
return 0;
}
#include<iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int MOD=1000000007;
const int p=10000019;
vector<int> ans;
//字符串hash
long long hasfunc(string str){
long long H=0;
for(int i=0;i<str.length();i++){
H=(H*p+str[i]-'a') % MOD;
}
return H;
}
int main(){
string str;
while(getline(cin,str),str!="#"){
long long id=hasfunc(str);
ans.push_back(id);
}
sort(ans.begin(),ans.end());
int count=0;
for(int i=0;i<ans.size();i++){
if(i==0 || ans[i]!=ans[i-1])
count++;
}
cout<<count<<'\n';
return 0;
}
输入两个长度均不超过1000的字符串,求他们的最长公共子串的长度
1.先分别对两个字符串的每个子串求出hash值(同时记录对应长度)
2.再找出两堆子串对应的hash值种相等的那些,便可以找到最大长度
时间复杂度是o(n2+m2)
#include<iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const int P=10000019;
const int MAXN=1010; //MAXN为字符串最大长度
//powP[i]存放P^i%MOD,H1和H2分别存放str1和str2的hash值
LL powP[MAXN],H1[MAXN]={0},H2[MAXN]={0};
//pr1存放str1的所有<子串hash值,子串长度>,ptr2同理
vector<pair<int, int>> pr1,pr2;
//init函数初始化powP函数
void init(int len){
powP[0]=1;
for(int i=1;i<=len;i++){
powP[i]=(powP[i-1]*P)%MOD;
}
}
//calH函数计算字符串str的hash值
void calH(LL H[],string &str){
H[0]=str[0];
for(int i=1;i<str.length();i++){
H[i]=(H[i-1]*P+str[i])%MOD;
}
}
//calSingleSubH计算H[i..j]
int calSingleSubH(LL H[],int i,int j){
if(i==0) return H[j];
return ((H[j]-H[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}
//calSubH计算所有子串的hash值,并将子串<子串hash值,子串长度>存入pr
void calSubH(LL H[],int len,vector<pair<int, int>>&pr){
for(int i=0;i<len;i++){
for(int j=i;j<len;j++){
int hashvalue=calSingleSubH(H, i, j);
pr.push_back(make_pair(hashvalue, j-i+1));
}
}
}
//计算pr1和pr2种相同的hash值,维护最大长度
int getMax(){
int ans=0;
for(int i=0;i<pr1.size();i++){
for(int j=0;j<pr2.size();j++){
if(pr1[i].first==pr2[j].first)
ans=max(ans,pr1[i].second);
}
}
return ans;
}
int main(){
string str1,str2;
getline(cin,str1);
getline(cin,str2);
init(max(str1.length(),str2.length()));
calH(H1, str1);
calH(H2, str2);
calSubH(H1, str1.length(), pr1);
calSubH(H2, str2.length(), pr2);
cout<<"ans="<<getMax()<<'\n';
return 0;
}
#include<iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MOD=1000000007;
const int P=10000019;
const int MAXN=1010; //MAXN为字符串最大长度
//powP[i]存放P^i%MOD,H1和H2分别存放str1和str2的hash值
LL powP[MAXN],H1[MAXN]={0},H2[MAXN]={0};
//pr1存放str1的所有<子串hash值,子串长度>,ptr2同理
vector<pair<int, int>> pr1,pr2;
//init函数初始化powP函数
void init(int len){
powP[0]=1;
for(int i=1;i<=len;i++){
powP[i]=(powP[i-1]*P)%MOD;
}
}
//calH函数计算字符串str的hash值
void calH(LL H[],string &str){
H[0]=str[0];
for(int i=1;i<str.length();i++){
H[i]=(H[i-1]*P+str[i])%MOD;
}
}
//calSingleSubH计算H[i..j]
int calSingleSubH(LL H[],int i,int j){
if(i==0) return H[j];
return ((H[j]-H[i-1]*powP[j-i+1])%MOD+MOD)%MOD;
}
//对称点为i,字符串长为len,在[l,r]里二分回文半径
//寻找最后一个满足条件“hashL=hashR"的回文半径
//等价于寻找一个满足条件“hashL!=hashR”的回文半径,然后减1即可
//isEven当求奇回文时,为0,求偶回文时为1
int binarySearch(int l,int r,int len,int i,int isEven){
while(l<r){ //当出现l==r时结束
int mid=(l+r)/2;
//左半子串hash值H1[H1L..H1R],右半子串hash值H2[H2L..H2R]
int H1L=i-mid+isEven,H1R=i;
int H2L=len-1-(i+mid),H2R=len-1-(i+isEven);
int hasL=calSingleSubH(H1, H1L, H1R);
int hasR=calSingleSubH(H2, H2L, H2R);
if(hasL!=hasR) r=mid; //hash值不等,说明回文半径
else l=mid+1; //hash值相等,说明回文半径>mid
}
return l-1; //返回最大回文半径
}
int main(){
string str;
getline(cin,str);
init(str.length()); //初始化powP
calH(H1, str);
reverse(str.begin(), str.end()); //反转字符串
calH(H2, str);
int ans=0;
//奇回文
for(int i=0;i<str.length();i++){
//二分上届为分界点i的左右长度的较小值加1
int maxLen=min(i,(int)str.length()-1-i)+1; //分界点i的回文串的半径长度,最多为一半
int k=binarySearch(0, maxLen, str.length(), i, 0);
ans=max(ans,k*2+1);
}
//偶回文
for(int i=0;i<str.length();i++){
//二分上届为分界点i的左右长度的较小值加1(注意左长为i+1)
int maxLen=min(i+1,(int)str.length()-1-i)+1;
int k=binarySearch(0, maxLen, str.length(), i, 1);
ans=max(ans,k*2);
}
cout<<ans<<'\n';
return 0;
}
时间复杂度为O(m+n)
next数组的求解过程:
//getNext求解长度为len的字符串s的next数组
void getNext(char s[],int len){
int j=-1;
next[0]=-1; //初始化next数组,令j=next[0]=-1
for(int i=1;i<len;i++){ //求解next[1]~next[len-1]
while(j!=-1 && s[i]!=s[j+1]){
j=next[j]; //不断令j=next[j], 直到j回退为-1,或是s[i]=s[j+1]成立
}
if(s[i]==s[j+1]){
j++; //则next[i]=j+1,先令j指向这个位置
}
next[i]=j;
}
}
此处定义一个文本串text和一个模式串pattern,然后判断模式串patterm是否是文本串text的子串,令i指向text的当前欲比较位,令j指向pattern中当前已被匹配的最后位,这样只要text[i]==pattern[j+1]成立,就说明pattern[j+1]也被成功匹配,此时让i,j加1以继续比较,直到j达到m-1时说明pattern是text的子串(m为模式串pattern的长度)
KMP算法的一般思路
//KMP算法,判断pattern是否是text的子串
bool KMP(char text[],char pattern[]){
int n=strlen(text),m=strlen(pattern); //字符串长度
getNext(pattern,m); //计算pattern的next数组
int j=-1;
for(int i=0;i<n;i++){ //试图匹配text[i]
while(j!=-1 && text[i]!=pattern[j+1]){
j=next[j]; //不断令j=next[j], 直到j回退到-1,或是text[i]=pattern[j+1]成立
}
if(text[i]==pattern[j+1]){
j++;
}
if(j==m-1){
return true;
}
}
return false;
}
------------------------------------------------
/*如何统计文本串text中模式串pattern出现的次数?
当j=m-1时表示pattern的一次成功完全匹配,此时令记录成功匹配次数加1,但问题在于从模式串哪个位置开始进行下一次匹配? next[j]
next[j]代表着整个模式串pattern的最长相等前后缀,从这个位置可以让j最大,即让成功匹配的部分最长,能保证不漏解
*/
//KMP算法,判断pattern在text中出现的次数
int KMP(char text[],char pattern[]){
int n=strlen(text),m=strlen(pattern); //字符串长度
getNext(pattern,m); //计算pattern的next数组
int j=-1;
int ans=0;
for(int i=0;i<n;i++){ //试图匹配text[i]
while(j!=-1 && text[i]!=pattern[j+1]){
j=next[j]; //不断令j=next[j], 直到j回退到-1,或是text[i]=pattern[j+1]成立
}
if(text[i]==pattern[j+1]){
j++;
}
if(j==m-1){
ans++;
j=next[j]; //j回退到next[j]继续匹配
}
}
return ans;
}
--PAT1057----
#include<iostream>
#include <string>
#include <stack>
using namespace std;
const int maxn=100010;
const int sqrN=316; //sqrt(100010),表示块内元素个数
stack<int> st;
int block[sqrN+1]; //记录每一块中的元素个数
int table[maxn]; //hash数组,记录当前元素存在个数
void peekMedian(int K){
int sum=0;
int id=0;
while(sum+block[id]<K){
sum=sum+block[id++];
}
int num=id*sqrN;
while(sum+table[num]<K){
sum=sum+table[num++];
}
cout<<num<<'\n';
}
void Push(int x){
st.push(x);
block[x/sqrN]++;
table[x]++;
}
void Pop(){
int x=st.top();
st.pop();
block[x/sqrN]--;
table[x]--;
cout<<x<<'\n';
}
int main(){
int x,query;
memset(block, 0, sizeof(block));
memset(table, 0, sizeof(table));
char cmd[20];
cin>>query;
for(int i=0;i<query;i++){
cin>>cmd;
if(strcmp(cmd, "Push")==0){
cin>>x;
Push(x);
}else if(strcmp(cmd, "Pop")==0){
if(st.empty()==true){
cout<<"Invalid\n";
}else{
Pop();
}
}else{
if(st.empty()==true){
cout<<"Invalid\n";
}else{
int k=st.size();
if(k%2==1) k=(k+1)/2;
else k=k/2;
peekMedian(k);
}
}
}
return 0;
}