说明
题目选自《算法竞赛入门经典》,题目先后顺序和它们在这本书里出现的顺序相同。
10340
字符串子序列:从s中删除一些字符,能否得到字符串t,如果是,输出Yes,否则,输出No
#include
int main(int argc, char** argv) {
std::string s, t;
int sb,se,tb,te;
while(std::cin>>t>>s){
sb=0;
se=s.size()-1;
tb=0;
te=t.size()-1;
while(tb=0 && s[se] != t[te])
--se;
if(sb==s.size() || se<0 || sb >= se){
std::cout<<"No"< se)
std::cout<<"No"<te)
std::cout<<"Yes"<
202
循环小数
给定一个数的分子和分母,输出它的循环小数及循环小数的长度
#include
#include
#include
679小球下落
一棵完全二叉树,节点按广度遍历的顺序编号1,2,...,2^n-1其中n是层数,根节点是第一层。每个节点有一个开关,开关开,小球流向右子树,否则就流向左子树。小球每落到一个节点上后,该节点的开关状态就发生改变。最开始,所有开关都是关的,求第n个球最终位置。
#include
int pow2(int n){
if(n<1)
return -1;
int rv=1;
while(n--)
rv=rv*2;
return rv;
}
int main(int argc, char** argv) {
int l;
while(true){
std::cin>>l;
if(l==-1)
break;
int d, n;
while(l--){
std::cin>>d>>n;
int r=pow2(d-1);
int incre=r/2;
while(incre){
if(n%2 == 0)
r+=incre;
n=(n+1)/2;
incre=incre/2;
}
std::cout<
572油田
求联通块个数,上下左右还有斜着的@都算同一块
其实就是用递归实现,符号说明:
0----*或者已经遍历过的@
@----没有遍历过
依次遍历图,遇到@,说明找到新块,于是将block增1,然后,递归将和它相连的@变成0
#include
static int a[100][100];
void dfs(int (&a)[100][100] , int r , int c , const int m, const int n){
if(r<0 || r>=m || c<0 ||c>=n )
return;
if(a[r][c] != -1)
return;
a[r][c]=0;
for(int i=-1 ; i <=1 ; ++i)
for(int j=-1 ; j<=1 ; ++j)
if(i || j)
dfs(a, r+i , c+j, m , n);
}
int main(int argc, char** argv) {
int m , n;
char temp;
while(true){
std::cin>>m>>n;
if(m==0)
break;
for(int i=0; i >temp;
if(temp=='*')
a[i][j]=0;
else
a[i][j]=-1;
}
int block=0;
for(int i=0; i
1599理想路径
理想路径:求出从节点1到节点n的最短路径,如果有多个解,输出边的字典序最小的那个。
1)错误的代码:
节点和边的数量在10^5数量级,显然不能用O(n*n)的时间和空间复杂度了,尤其是空间。。。
采用vector
之所以采用multimap,是因为想给这些颜色排个序(后面证明这个想法并不能实现按字典排序T_T),尽管查找单个节点花费O(logn),但遍历整个节点并非是O(nlogn),而是O(n),因此采用map并不会带来时间上的开销。
length记录起点到每一个节点的长度,-1表示还没遍历到
father记录最短路径下的父节点
#include
#include
#include
如果不按字典序,或者说,不用处理重复元素(大多数都是这两种情况,这个题是有点。。。非主流。。。),那么上述代码是对的,按字典序后,尽管使用multimap存储相邻节点,仍然不能保证正确,例如测试样例
4 6
1 2 1
1 3 2
3 4 3
2 3 1
2 4 4
3 1 1
对于节点1,边121和311颜色相同,但根据广度优先的原理,边121先被遍历,这样,首先到达4的路径就是1->2->4,边的字典序是14,然而,正确的解确是1->3->4,字典序是13. 根本原因就是它不能正确处理颜色相同的情况。
尽管不正确,但仍能学到广度优先搜索的方法,以及stl中一些容器的使用。
2)改进后的解法
可以考虑倒着进行bfs,也就是说,从终点开始,通过bfs寻找它到起点的最短路径。为了让结果取字典序,除了判断节点是否被遍历过外,还要判断如果遍历过节点最短路径和当前计算的最短路径相同,则判断二者字典序,然后选择字典序最小的那个
#include
#include
#include
UVa725
输入正整数n,输出所有abcde/efghil=n的表达式,其中abcdefghil是0到9的一个排列,有前导0, n 的范围[2,79].
暴力解,一共枚举A(10,5)中情况
通过dfs的方式进行字典序搜索,迭代次数是109876,当然,暴力点的话直接五层for循环,迭代次数10^5,也是可以解决问题的。
注意输出格式:当输入0的时候,表示结束,没有任何空格
还有一个坑爹的格式要求是:最后一个有效输出后没有空格,也就是输入0之前的那个输入不产生空格
#include
#include
#include
//const int flag=0^1^2^3^4^5^6^7^8^9;//bug
int judge(int *a, int v){
int r=0;
for(int i=0 ; i < 5 ; ++i)
r=r*10+a[i];
if(r%v)
return -1;
int u=r/v;
for(int i=5; i< 10 ;++i){
a[i]=u%10;
u=u/10;
}
int aa[10];
memset(aa, -1 , 10*sizeof(int));
for(int i=0 ; i < 10; ++i){
if(aa[a[i]] != -1)
return -1;
else
aa[a[i]]=a[i];
}
return r;
}
bool is_exist(int *a, int k, int n){
for(int i=0 ; i < n ; ++i )
if(a[i]==k)
return true;
return false;
}
int count=0;
void dfs(int a[10] , int n, int v, std::vector &r){
if(n==5){
int j;
if( (j=judge(a, v)) != -1 ){
r.push_back(j);
}
return;
}
for(int i=0; i<10 ;++i){
if(!is_exist( a, i , n )){
a[n]=i;
dfs(a, n+1,v, r);
}
}
}
int main()
{
int a[10];
int v;
bool blank=false;
while(std::cin>>v){
if(v==0)
break;
if(blank)
std::cout< r;
dfs(a, 0 , v, r);
if(r.empty())
std::cout<<"There are no solutions for "<
UVa10976
输入正整数k,找出所有的x>y,满足1/k=1/x+1/y
解法:暴力枚举,枚举y,枚举范围[k+1,2*k]
#include
#include
#include
int main()
{
int k;
while((scanf("%d", &k))==1){
if(k==0)
break;
std::vector x;
for(int i=k+1 ; i < 2*k+1 ; ++i)
if(i*k%(i-k)==0)
x.push_back(i);
printf("%d\n", x.size());
for(size_t i=0 ; i < x.size() ; ++i){
printf("1/%d = 1/%d + 1/%d\n", k, k*x[i]/(x[i]-k), x[i]);
}
}
return 0;
}
UVa524 素数环
把整数1,2,3,...,n组成一个环,使得相邻数的和都是素数,环从数字1开始。
暴力枚举解决,为了减少枚举量,采用回溯法。
1)一个解法
这个解法并没有ac,出错原因是它的输出没有按字典排序
#include
#include
#include
#include
std::vector prim{1,2,3,5,7,11,13,17,19,23,29,31};
void dfs(int *A, int n , int cur){
if(cur==n && std::binary_search(&prim[0], &prim[0]+12, A[n-1]+A[0])){
std::cout<>n){
if(n==0)
break;
if(blanc)
std::cout<
2)对上述解法进行改进,使它按字典序输出
#include
#include
#include
#include
std::vector prim{1,2,3,5,7,11,13,17,19,23,29,31};
void dfs(int *A, int n , int cur){
if(cur==n && std::binary_search(&prim[0], &prim[0]+12, A[n-1]+A[0])){
std::cout<>n){
if(n==0)
break;
if(blanc)
std::cout<
3)用一个数组记录是否被用到来进行深度优先搜索:
#include
#include
#include
#include
std::vector prim{1,2,3,5,7,11,13,17,19,23,29,31};
bool is_prim(int value){
return std::binary_search(&prim[0], &prim[0]+12, value);
}
void dfs(int *A, int *set_, int n , int cur){
if(cur==n && is_prim(A[n-1]+1)){
std::cout<>n){
if(n==0)
break;
if(blanc)
std::cout<
UVa124 困难的串
题目
对于一个字符串,如果存在相同且相邻的两个子串,则该字符串是“容易的串”,否则就叫困难串。对于基数是n的字符串,字符由A,B,... (n个字符)组成,给定n和L,求基数为n的字符串中第L大的困难串。
解法
暴力解,从第一个困难串开始,根据当前困难串,计算下一个困难串,一直计算到第L大的困难串。
其实这个也是深度优先搜索过程,跟之前有点不同的是,一旦搜索到想要的答案,就立刻终止。。。
#include
#include
bool is_hard(const int *A, const int n, const int cur){
if(A==NULL || cur>=n)
return false;
for(int i=1; 2*i<=cur+1 ; ++i){
int j;
for(j=0; j=n || count<=0 || l<1)
return true;
bool ok=true;
if(cur==0){
for(int i=1; i=count){
print_hard(A, cur+1);
return false;
}
ok=dfs(A, n, cur+1, tot, count, l);
}
}else{
for(int i=1; i=count){
print_hard(A,cur+1);
return false;
}
ok=dfs(A, n, cur+1, tot, count, l);
}
}
}
return ok;
}
int main()
{
int n, l;
//bool blanc=false;
int A[81];
/*
FILE *fp;
if((fp=freopen("/home/xmqv/code/output.tex", "w", stdout))==NULL)
std::cout<<"can't open testfile!"<>n>>l){
if(n==0)
break;
//if(blanc)
//std::cout<
UVa140 Bandwidth
解法:深度优先搜索+剪枝
#include
#include
#include