UVa online judge

说明

题目选自《算法竞赛入门经典》,题目先后顺序和它们在这本书里出现的顺序相同。

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 

int main(int argc, char** argv) {
    int numerator, denominator;
    while(std::cin>>numerator>>denominator){
        std::vector decimal;
        int itger=numerator/denominator;
        int remainder=(numerator%denominator)*10;
        std::map rem2idx;
        int t;
        int idx=0;
        while(true){
            rem2idx[remainder]=idx++;
            t=remainder/denominator;
            decimal.push_back(t);
            remainder=(remainder%denominator)*10;
            if(rem2idx.find(remainder) != rem2idx.end())
                break;
        }
        std::cout<=50){
            int i;
            for(i=0; i<50; ++i)
                std::cout<

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 > G, G的小标i表示节点i,G[i]是个multimap,键是color,值是和i相邻的节点。
之所以采用multimap,是因为想给这些颜色排个序(后面证明这个想法并不能实现按字典排序T_T),尽管查找单个节点花费O(logn),但遍历整个节点并非是O(nlogn),而是O(n),因此采用map并不会带来时间上的开销。
length记录起点到每一个节点的长度,-1表示还没遍历到
father记录最短路径下的父节点

#include 
#include 
#include 
#include 
#include 


void print_path(std::vector &father, int n){
    if(n==0){
        std::cout<<1<>n>>m){
        if(n==0)
            break;
        std::vector father(n,-1);
        std::vector length(n,-1);
        std::vector > G(n);
        int p=m;
        while(p--){
            std::cin>>node1>>node2>>color;
            G[node1-1].insert(std::make_pair(color, node2-1));
            G[node2-1].insert(std::make_pair(color, node1-1));
            //G[node1-1][color]=node2-1;
            //G[node2-1][color]=node1-1;
        }
        std::deque d;
        d.push_back(0);
        length[0]=0;
        int curr;
        while(!d.empty()){
            curr=d.front();
            d.pop_front();
            for(auto &s : G[curr]){
                if(length[s.second]==-1){
                    d.push_back(s.second);
                    length[s.second]=length[curr]+1;
                    father[s.second]=curr;
                }
            }
            std::cout<

如果不按字典序,或者说,不用处理重复元素(大多数都是这两种情况,这个题是有点。。。非主流。。。),那么上述代码是对的,按字典序后,尽管使用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 
#include 
#include 

void print_path(std::vector &child, std::vector &color,int n){
    int p=0;
    std::cout<>n>>m){
        if(n==0)
            break;
        std::vector child(n,-1);
        std::vector length(n,-1);
        std::vector vcolor(n,-1);
        std::vector > G(n);
        int p=m;
        while(p--){
            std::cin>>node1>>node2>>color;
            G[node1-1].insert(std::make_pair(color, node2-1));
            G[node2-1].insert(std::make_pair(color, node1-1));
        }
        std::deque d;
        d.push_back(n-1);
        length[n-1]=0;
        int curr;
        while(!d.empty()){
            curr=d.front();
            d.pop_front();
            for(auto &s : G[curr]){
                if(length[s.second]==-1){
                    d.push_back(s.second);
                    length[s.second]=length[curr]+1;
                    child[s.second]=curr;
                    vcolor[s.second]=s.first;
                }else if(length[s.second]==length[curr]+1){
                    if(s.first

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 "< 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 
#include 
#include 

void dfs(char A[], int n, int cur, int &min_, std::map > &G, std::vector &result_){
    if(A==NULL || n<1 || cur>n || cur<0 || min_<1 || G.empty())
        return;
    if(cur==n){
        int max_=-1;
        for(int i=0; i< cur ; ++i)
            for(int j=i+1; j max_)
            for(int i=0; i= min_)
            continue;
            */
        ok=true;
        for(int j=0;  j>s){
        if(s==std::string("#")){
            break;
        }
        std::map > G;
        for(int i=0; i &temp=G[c];
            i=i+2;
            for(; i result_(8);
        dfs(A, min_, 0, min_, G, result_);
        if(min_==G.size())
            min_=0;
        for(int i=0; i "<

你可能感兴趣的:(UVa online judge)