zoukankan      html  css  js  c++  java
  • poj 几道简单的搜索题(三)

    题目:poj 2531

    题意:

    给出n(n<=20)个点,及点与点之间的权值,把这n个点划分成两个集合,使这两个集合中点与点之间的边权和最小?

    分析:

    n=20,暴力枚举的时间复杂度才O(2^20*C),C是求和的时间常数。2000ms的时间足够了。暴力枚举的话可以子集枚举和递归(时间接近1000ms)。

    这题递归的话可以剪枝,可以优化到32ms,方法是参考:http://blog.csdn.net/martin31hao/article/details/8098302


    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=22;
    int n,ans;
    int w[N][N];
    bool in[N];
    void dfs(int k,int sum)
    {
        in[k]=1;  //0表示在0集合,1表示在1集合
        int t=sum;
        for(int i=0;i<n;i++)
            if(in[i])t-=w[k][i];
            else t+=w[k][i];
        if(t>ans)ans=t;
        for(int i=k+1;i<n;i++)  //看下一个点
        if(t>sum){    //剪枝,只有t>sum才考虑以后的选择情况
            dfs(i,t); //把i放到1集合
            in[i]=0; //不放
        }
    }
    int main()
    {
        memset(in,0,sizeof(in));
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)scanf("%d",&w[i][j]);
        ans=0;
        dfs(0,0);
        printf("%d
    ",ans);
        return 0;
    }
    题目:poj 1416

    题意:

    整数划分问题,要求把所给整数划分,使得划分得到的的数的和尽量接近一个目标数字。

    分析:

    枚举划分的个数,dfs分配划分的位置,然后把划分的数加起来求和即可。

    我是用一个string保存划分位置,最后再按照string保存的划分位置再求和。

    剪枝的话应该是每划分一次就把所得到的和,与未划分的数加起来,然后与已经得到最优解比较,判断是否剪枝即可。

    我的代码没优化,懒得改了QAQ。

    #include<cstdio>
    #include<iostream>
    #include<stack>
    #include<vector>
    #include<cstring>
    using namespace std;
    int n,ans,total,ansnum,len;
    vector<int>vec;
    string as;
    void dfs(int tot,int id,int k,string s)
    {
        if(tot==0){
            int i=0,sum=0;
            int pre=0;
            for(;i<=id;i++){
                int x=s[i]-'0';
                int j=x-1,w=1,num=0;
                while(j>=pre){
                    num+=vec[j--]*w;
                    w*=10;
                }
                pre=x;
                sum+=num;
            }
            if(sum>ans&&sum<=total)ans=sum,ansnum=1,as=s,len=id;
            else if(sum==ans)ansnum++;
            return;
        }
        for(int i=k+1;i<vec.size();i++){  //枚举划分的位置
            string t=s;
            t[id]=(char)(i+'0');
            dfs(tot-1,id+1,i,t);
        }
    }
    void change(int x)
    {
        stack<int>s;
        while(x){
            s.push(x%10);
            x/=10;
        }
        while(!s.empty())vec.push_back(s.top()),s.pop();
    }
    int main()
    {
        while(~scanf("%d%d",&total,&n)&&(total+n)){
            vec.clear();
            ans=-1;
            change(n);
            string s="1234567";
            for(int i=0;i<vec.size();i++){ //枚举划分的个数
                s[i]=(char)('0'+vec.size());
                dfs(i,0,0,s);
            }
            if(ans==-1)printf("error
    ");
            else if(ansnum>1)printf("rejected
    ");
            else{
                printf("%d",ans);
                int i=0,sum=0;
                int pre=0;
                for(;i<=len;i++){
                    int x=as[i]-'0';
                    int j=x-1,w=1,num=0;
                    while(j>=pre){
                        num+=vec[j--]*w;
                        w*=10;
                    }
                    pre=x;
                    printf(" %d",num);
                }
                printf("
    ");
            }
        }
        return 0;
    }
    

    题目:poj 2676

    题意:

    完成数独9*9,使每一行,每一列,每一小块3*3,都是由1-9组成

    分析:

    把没放数的位置先找出来,然后dfs一个个放数。用三个数组标记一下以放数的行,列和块。

    看Discuss说反搜更快。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int N=11;
    typedef pair<int,int>pii;
    pii q[N*N]; 
    bool cow[N][N],row[N][N],blo[N][N]; //列,行,块
    int a[N][N];
    int id[9][9]={0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2, //每个位置所属的块
                    3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
                    6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8};
    bool flag;
    int cnt;
    bool dfs(int s)
    {
        if(flag)return 1;
        if(s==cnt){
            flag=1;return 1;
        }
        bool ok=1;
        int r=q[s].first,c=q[s].second;
        for(int k=1;k<=9;k++){
            if(!row[r][k]&&!cow[c][k]&&!blo[id[r][c]][k]){
                a[r][c]=k; row[r][k]=cow[c][k]=blo[id[r][c]][k]=1;
                if(dfs(s+1))return 1;
               row[r][k]=cow[c][k]=blo[id[r][c]][k]=0;//a[r][c]=0;
            }
        }
        return 0;
    }
    int main()
    {
        int T;scanf("%d",&T);
        char s[11];
        while(T--){
            memset(row,0,sizeof(row));
            memset(cow,0,sizeof(cow));
            memset(blo,0,sizeof(blo));
            flag=0;
            cnt=0;
            for(int i=0;i<9;i++){
                scanf("%s",s);
                for(int j=0;j<9;j++){
                    a[i][j]=s[j]-'0';
                    int k=a[i][j];
                    if(k!=0)row[i][k] =cow[j][k] =blo[id[i][j]][k]=true;
                    else q[cnt++]=make_pair(i,j);
                }
            }
            dfs(0);
            for(int i=0;i<9;i++){
                for(int j=0;j<9;j++)printf("%d",a[i][j]);
                printf("
    ");
            }
    
        }
        return 0;
    }

    题目:poj 1129

    题意:

    图的染色问题,相邻点不能染同一种颜色,问需要最少颜色数?

    分析:

    dfs,依次枚举每个点,给他分配一种可以染的颜色,然后这种颜色从与它相邻的点的可染色中删除,然后再枚举下一个点,继续同样操作。

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    const int N=30;
    vector<int>g[N]; //存边
    int n;
    bool vis[N][N];
    void dfs(int u)
    {
        if(u==n)return;
        int i;
        for(i=0;i<n;i++){
            if(!vis[u][i]){vis[u][i]=1;break;} //找一种可染色
        }
        for(int j=0;j<g[u].size();j++){  
            vis[g[u][j]][i]=1;  //邻接点这种颜色不能用了
        }
        dfs(u+1);
    }
    char s[N];
    int main()
    {
        while(~scanf("%d",&n)&&n){
            for(int i=0;i<n;i++){
                scanf("%s",s);
                int len=strlen(s);
                g[s[0]-'A'].clear();
                if(len<=2)continue;
                for(int j=2;j<len;j++)
                    g[s[0]-'A'].push_back(s[j]-'A');
            }
            memset(vis,0,sizeof(vis));
            dfs(0);
            int ans=-1;
            for(int i=0;i<n;i++){
                int j;
                for(j=0;j<n;j++)if(!vis[i][j])break;
                if(j>ans)ans=j;
            }
            if(ans==1)printf("1 channel needed.
    ");
            else printf("%d channels needed.
    ",ans);
        }
        return 0;
    }
    









  • 相关阅读:
    伪静态
    query 文件提交 +php后台入库
    PHP实现URL长连接转短连接方法
    通过经纬度获取所属城市信息
    PHP 学习之路1
    Linux云服务器安装tomcat
    linux下svn服务器搭建步骤
    HttpServletrequest 与HttpServletResponse总结
    HTML5基础
    Ajax相关总结
  • 原文地址:https://www.cnblogs.com/01world/p/5762840.html
Copyright © 2011-2022 走看看