• 洛谷——搜索


    1.洛谷 P1019 单词接龙

    题目描述

    单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如 beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at 和 atide 间不能相连。

    输入输出格式

    输入格式:

    输入的第一行为一个单独的整数n (n<=20)表示单词数,以下n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在.

    输出格式:

    只需输出以此字母开头的最长的“龙”的长度

    输入输出样例

    输入样例#1:
    5
    at
    touch
    cheat
    choose
    tact
    a
    
    输出样例#1:
    23           (连成的“龙”为atoucheatactactouchoose)   

    说明

    NOIp2000提高组第三题

    思路:

      输入之后要先检查能不能接龙,如果能进行dfs,搜索最长的龙

    (⊙v⊙)嗯~ 代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,maxn,idx[25];
    char first;
    char word[25][100];
    int lian[25][25];//0为不能连接,否则为能连接,最大连接长度 
    bool check(int i,int j,int pos,int l1,int l2)   //检查能否将i的后半部分与j的前半部分接起来 
    {         //两个字符串,i接的起点,两个字符串的长度 
        if(l1-pos>=l2)return false;   //>:一定不能接,=:就算能接也单词之间包含 
        for(int k=pos,h=0;k<l1;k++,h++)if(word[i][k]!=word[j][h])return false;//不匹配 
        return true;
    }
    int dfs(int i)
    { 
        int num=0;//从i开始的最长长度 
        for(int j=1;j<=n;j++)
        {
            if(lian[i][j] && idx[j]<2){idx[j]++;num=max(num,dfs(j)+lian[i][j]);idx[j]--;}
        }     //可连接,注意不能等于2,因为马上就要idx++,就是3了 
        return num;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%s",word[i]);
        do{scanf("%c",&first);} while(!isalpha(first)); //读入字母,小心读入‘
    ’ 
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
          {          
              int l1=strlen(word[i]),l2=strlen(word[j]);
              for(int pos=l1-1;pos>0;pos--) //pos>0而非>=的原因:单词不能有包含关系 
                  if(check(i,j,pos,l1,l2)){lian[i][j]=l2-(l1-pos);break;}//这个lian是把j接在i后j的长度 
          }                                          //break:贪心,接的部分越少则总长度越长 
        for(int i=1;i<=n;i++)if(word[i][0]==first)
        {
            idx[i]++; 
            maxn=max(maxn,(int)strlen(word[i])+dfs(i)); 
            idx[i]--;  //不要忘了减回来 
        }
        cout<<maxn<<"
    ";    
        return 0;
    }

    2.洛谷 P1034 矩形覆盖

    题目描述

    在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),见图一。

    这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。当 k=2 时,可用如图二的两个矩形 sl,s2 覆盖,s1,s2 面积和为 4。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。

    输入输出格式

    输入格式:

    n k xl y1 x2 y2 ... ...

    xn yn (0<=xi,yi<=500)

    输出格式:

    输出至屏幕。格式为:

    一个整数,即满足条件的最小的矩形面积之和。

    输入输出样例

    输入样例#1:
    4 2
    1 1
    2 2
    3 6
    0 7
    
    输出样例#1:
    4
    思路:

      最最保险的做法:dfs+剪枝,当k>=4时也能做。

      原则:枚举每一个点,可以任意加入到k个矩形中的某一个,从而得到最优解。

      原理:易证明对于每一种i(i<k)个矩形的情形,其结果一定不是最优的(可将其中某个矩形再次划分)

      每个矩形只需记录其4至点,即可求面积。

    
    
    #include<iostream>
    #include<cstdio>
    using namespace std;
    
    int n,k,ans=0x7fffffff;
    struct Coordinate{
        int x,y; 
    }nate[102];
    
    struct Rectangle{
        int urcorner,ulcorner,dlcorner,drcorner;
        bool flag;
    }rect[12];
    
    bool in(Rectangle a,int x,int y){
        if(x>=a.ulcorner&&x<=a.urcorner&&y>=a.dlcorner&&y<=a.drcorner) return 1;
        return 0;
    }
    
    int judge(Rectangle a,Rectangle b){
        if(in(a,b.ulcorner,b.drcorner)) return 1;
        if(in(a,b.ulcorner,b.dlcorner)) return 1;
        if(in(a,b.urcorner,b.drcorner)) return 1;
        if(in(a,b.urcorner,b.dlcorner)) return 1;
        return 0;
    }
    
    void dfs(int num){
        int area=0;
        for(int i=1; i<=k; i++) {
            if(rect[i].flag) {
                for(int j=i+1;j<=k;j++)
                    if(rect[i].flag&&judge(rect[i],rect[j])) return ;
            }
            area+=(rect[i].urcorner-rect[i].ulcorner)*(rect[i].drcorner-rect[i].dlcorner);
        }
        if(area>=ans) return ;
        if(num>n) {
            ans=area;
            return ;
        }
        for(int i=1; i<=k; i++){
            Rectangle tmp=rect[i];
            if(!rect[i].flag) {
                rect[i].flag = 1;
                rect[i].ulcorner = rect[i].urcorner = nate[num].x;
                rect[i].drcorner = rect[i].dlcorner = nate[num].y;
                dfs(num+1);
                rect[i] = tmp;
                break ;
            }
            else {
                rect[i].ulcorner = min(rect[i].ulcorner,nate[num].x);
                rect[i].dlcorner = min(rect[i].dlcorner,nate[num].y);
                rect[i].urcorner = max(rect[i].urcorner,nate[num].x);
                rect[i].drcorner = max(rect[i].drcorner,nate[num].y);
                dfs(num+1);
                rect[i] = tmp;
            }
        }
    }
    
    int main() {
        cin>>n>>k;
        for(int i=1; i<=n; i++) 
            cin>>nate[i].x>>nate[i].y;
        dfs(1);
        cout<<ans<<endl;
        return 0;
    }
    3.洛谷 P1041 传染病控制

    题目背景

    近来,一种新的传染病肆虐全球。蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延。不幸的是,由于人们尚未完全认识这种传染病,难以准确判别病毒携带者,更没有研制出疫苗以保护易感人群。于是,蓬莱国的疾病控制中心决定采取切断传播途径的方法控制疾病传播。经过 WHO(世界卫生组织)以及全球各国科研部门的努力,这种新兴传染病的传播途径和控制方法已经研究清楚,剩下的任务就是由你协助蓬莱国疾控中心制定一个有效的控制办法。

    题目描述

    研究表明,这种传染病的传播具有两种很特殊的性质;

    第一是它的传播途径是树型的,一个人X只可能被某个特定的人Y感染,只要Y不得病,或者是XY之间的传播途径被切断,则X就不会得病。

    第二是,这种疾病的传播有周期性,在一个疾病传播周期之内,传染病将只会感染一代患者,而不会再传播给下一代。

    这些性质大大减轻了蓬莱国疾病防控的压力,并且他们已经得到了国内部分易感人群的潜在传播途径图(一棵树)。但是,麻烦还没有结束。由于蓬莱国疾控中心人手不够,同时也缺乏强大的技术,以致他们在一个疾病传播周期内,只能设法切断一条传播途径,而没有被控制的传播途径就会引起更多的易感人群被感染(也就是与当前已经被感染的人有传播途径相连,且连接途径没有被切断的人群)。当不可能有健康人被感染时,疾病就中止传播。所以,蓬莱国疾控中心要制定出一个切断传播途径的顺序,以使尽量少的人被感染。

    你的程序要针对给定的树,找出合适的切断顺序。

    输入输出格式

    输入格式:

    输入格式的第一行是两个整数n(1≤n≤300)和p。接下来p行,每一行有两个整数i和j,表示节点i和j间有边相连(意即,第i人和第j人之间有传播途径相连)。其中节点1是已经被感染的患者。

    输出格式:

    只有一行,输出总共被感染的人数。

    输入输出样例

    
    
    输入样例#1:
    7 6
    1 2
    1 3
    2 4
    2 5
    3 6
    3 7
    
    输出样例#1:


    (⊙v⊙)嗯~ 代码:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int ans,tot,n,p,edge_head[301],tree_head[301],num_edge,num_tree,maxn;
    bool vis[301];
    int d[301][301];
    
    struct Edge{
        int pre,to;
    }edge[602],tree[602]; 
    
    void edge_add(int pre,int to) {
        edge[++num_edge].pre = edge_head[pre];
        edge[num_edge].to = to;
        edge_head[pre] = num_edge;
    }
    
    void tree_add(int x,int y){
        tree[++num_tree].pre = tree_head[x];
        tree[num_tree].to = y;
        tree_head[x] = num_tree;
    }
    
    void build_tree(int x) { 
        for(int i=edge_head[x];i;i=edge[i].pre) {
            if(!vis[edge[i].to]) {
                vis[edge[i].to] = true;
                tree_add(x,edge[i].to);
                build_tree(edge[i].to);
            }
        }
    }
    
    void depth(int x,int deep){ //计算深度 
        d[deep][++d[deep][0]]=x;
        if(deep>maxn) maxn=deep;
        for(int i=tree_head[x];i;i=tree[i].pre) {
            depth(tree[i].to,deep+1);
        }
    }
    
    int change(int x,bool VIS[]){
        int s=0;
        for(int i=tree_head[x];i;i=tree[i].pre) {
            if(!VIS[tree[i].to]){
                vis[tree[i].to] = true;
                VIS[tree[i].to] = true;
                s+=change(tree[i].to,VIS)+1;
            }
        }
        return s;
    }
    
    void change2(int x,bool VIS[]){
        for(int i=tree_head[x];i;i=tree[i].pre) {
            if(VIS[tree[i].to]) {
                vis[tree[i].to] = false;
                VIS[tree[i].to] = false;
                change2(tree[i].to,VIS);
            }
        }
    }
    
    void dfs(int num,int tot) {
        if(num==maxn+1){
            if(ans<tot) ans = tot;
            return ;
        }
        bool VIS[301]; 
        memset(VIS,0,sizeof(VIS));
        int sum=0;
        for(int i=1; i<=d[num][0];i++) {
            if(!vis[d[num][i]]) {
                int x=change(d[num][i],VIS)+(vis[d[num][i]]==0);
                vis[d[num][i]] = true;
                dfs(num+1,tot+x);
                vis[d[num][i]] = false;
                change2(d[num][i],VIS);
                sum++;
            }
        }
        if(sum==0) {
            if(ans<tot) ans=tot;
        }
    }
    
    int main() {
        cin>>n>>p;
        int u,v;
        for(int i=1; i<=p; i++) {
            cin>>u>>v;
            edge_add(u,v);
            edge_add(v,u);
        }
        vis[1]=true;
        build_tree(1);
        depth(1,0);
        memset(vis,0,sizeof(vis));
        dfs(1,0);
        cout<<n-ans<<endl;
        return 0;
    }

    自己选的路,跪着也要走完!!!

    
    
  • 相关阅读:
    变量可变性问题
    Android 创建Listener监听器形式选择:匿名内部类?外部类?
    linux下安装zookeeper
    翻页工具类
    将哈夫曼树转化成二叉树
    Activity的启动流程分析
    题目1186:打印日期
    数据库设计--数据流图(DFD)
    c#基础之数组
    10.3.1 一个CONNECT BY的样例
  • 原文地址:https://www.cnblogs.com/wsdestdq/p/6853077.html
Copyright © 2020-2023  润新知