• 咸鱼烤前的垂死挣扎


    敲黑板当当当~ 

    从今晚(28)起,日更 “咸鱼烤前的垂死挣扎”。

    日更的内容是对当天学习的模板做一个小小的总结

    日更的的口号是——

              不是还没到最后一刻嘛~

         小哥哥再坚持一下嘛~ 


    搜索


    P1379 八数码难题

    题面:

    在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

    思路:

    隐形图要做转化处理(压缩,解压),然后就是跑上一圈BFS啦~

    注意特判(^U^)ノ~YO

    (听说还可以用康托展开处理,待我学会去去就来~)

     1 #include<cstdio>
     2 #include<queue>
     3 #include<iostream>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 struct node{
     8     string s;
     9     int step;
    10 }a,e;
    11 int sum,ans,tot;
    12 int dx[4]={-1,0,0,1},dy[4]={0,1,-1,0};
    13 char b[3][3];
    14 string n,m;
    15 bool flag[88888888];
    16 queue <node > q;
    17 
    18 string change(){
    19     string c;
    20     sum=0;
    21     for(int i=0;i<3;i++)
    22         for(int j=0;j<3;j++){
    23             c+=b[i][j];
    24             if(!(i==2&&j==2))sum=sum*10+b[i][j]-'0';    //注意求的是前 8位的和 
    25         }
    26     return c;
    27 }
    28 
    29 void bfs(){
    30     while(!q.empty()){
    31         int tot=0,x,y;
    32         a=q.front();
    33         q.pop();
    34         for(int i=0;i<3;i++)        // 解压 
    35             for(int j=0;j<3;j++){
    36                 if(a.s[tot]=='0') x=i,y=j;
    37                 b[i][j]=a.s[tot++];
    38             }
    39         for(int i=0;i<4;i++){        // 四个方向扫一遍 
    40             if(x+dx[i]>-1&&x+dx[i]<3&&y+dy[i]>-1&&y+dy[i]<3){
    41                 swap(b[x][y],b[x+dx[i]][y+dy[i]]);
    42                 e.s=change();    // 压缩->字符串 
    43                 if(e.s=="123804765"){
    44                     printf("%d",a.step+1);
    45                     exit(0);
    46                 }
    47                 if(!flag[sum]){
    48                     flag[sum]=1;
    49                     e.step=a.step+1;
    50                     q.push(e);
    51                     
    52                 }
    53                 swap(b[x][y],b[x+dx[i]][y+dy[i]]);    //回溯 
    54             }
    55         }
    56     }
    57 }
    58     
    59 int main()
    60 {
    61     cin>>n;
    62     m="123804765";
    63     a.s=n,a.step=0;
    64     q.push(a);
    65     for(int i=0;i<8;i++) sum=sum*10+n[i]-'0';
    66     for(int i=0;i<8;i++) ans=ans*10+m[i]-'0';
    67     flag[sum]=1;
    68     
    69     if(sum==ans) printf("0");    //注意特判 
    70     else bfs();
    71     
    72     return 0;
    73 }

     继续练我可怜的广搜!

    P2296 寻找道路

    题面:

    在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

      1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
      2. 在满足条件1的情况下使路径最短。

    注意:图 G 中可能存在重边和自环,题目保证终点没有出边。

    思路:

      1.  从终点反向BFS,求出所有可以到达终点的点   available[]

      2.  对每个点判断是否自己指向的节点都可以到达终点  ans[]

      3.  从起点正向BFS,求最短路

    总结:

      未知的起点,确定的终点。反向跑图。

     1 #include<cstdio>
     2 #include<queue>
     3 #include<vector>
     4 #define N 10010
     5 using namespace std;
     6 int read(){
     7     int x=0,f=1; char c=getchar();
     8     while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
     9     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    10     return f*x;
    11 }
    12 int n,m,s,t;
    13 int ava[N],ans[N],dis[N];//available
    14 queue < int > q;
    15 vector < int > cd[N];
    16 vector < int > rd[N];
    17 int main()
    18 {
    19     n=read(),m=read();
    20     for(int x,y,i=1;i<=m;i++){
    21         x=read(),y=read();
    22         rd[y].push_back(x);
    23         cd[x].push_back(y);
    24     }
    25     s=read(),t=read();
    26     ava[t]=1,q.push(t);
    27     while(!q.empty()){
    28         int u=q.front();
    29         q.pop();
    30         for(int i=0;i<rd[u].size();i++){
    31             int v=rd[u][i];
    32             if(!ava[v]){
    33                 ava[v]=1;
    34                 q.push(v);
    35             }
    36         }
    37     }
    38     if(!ava[s]){ 
    39         printf("-1"); return 0;
    40     }
    41     for(int i=1;i<=n;i++){
    42         if(ava[i]){
    43             int k=0;
    44             for(int j=0;j<cd[i].size();j++){
    45                 if(!ava[cd[i][j]]){
    46                     k=1;
    47                     break;
    48                 }
    49             }
    50             if(k==0) ans[i]=1;
    51         }
    52     }
    53     dis[s]=1,q.push(s);
    54     while(!q.empty()){
    55         int u=q.front();
    56         q.pop();
    57         if(u==t){
    58             printf("%d",dis[t]-1);
    59             return 0;
    60         }
    61         for(int i=0;i<cd[u].size();i++){
    62             int v=cd[u][i];
    63             if(ans[v]&&!dis[v]){
    64                 dis[v]=dis[u]+1;
    65                 q.push(v);
    66             }
    67         }
    68     }
    69     return 0;
    70 }

    DP

    • 区间DP

    使用特征: 每次可以消去一个区间,之后左右两边会合并起来。具有最优子问题结构且状态满足无后效性。

    解法 先枚举  区间长度 / 操作次数 , 再枚举  左端点 / 起始位置 , 后枚举  区间断点 / 结束位置  进行转移

    (一)  czy把妹   (见模拟赛篇)

     

     (二) 能量项链

    题面:

    Mars星球上,每个Mars人都随身佩带着一串能量项链。在项链上有NN颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m×r×n(Mars单位),新产生的珠子的头标记为m,尾标记为n。

    需要时,Mars人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

     

    特别注意:

    并未要求按顺序合并,事实说明按顺时针方向摆放珠子,合并时可以选择任意相邻的两个珠子合并,只要总能量最大即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define re register
     4 #define in inline
     5 #define N 2000
     6 using namespace std;
     7 int read(){
     8     int x=0,f=1; char c=getchar();
     9     while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
    10     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    11     return x*f;
    12 }
    13 int n,ans;
    14 int head[N],tail[N],f[N][N];
    15 int main()
    16 {
    17     n=read();
    18     for(re int i=1;i<=n;i++) head[i]=head[n+i]=read();
    19     for(re int i=1;i<=n;i++) tail[i]=tail[n+i]=head[i+1];
    20     tail[n]=tail[2*n]=head[1];
    21     
    22     for(int t=1;t<=n-1;t++)  //合并次数
    23         for(int i=1;i<=2*n-t;i++){  //起始位置
    24             int j=i+t;  //计算结束位置
    25             for(int k=i;k<=j-1;k++)  //决策
    26                 f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+head[i]*tail[k]*tail[j]);
    27         }
    28     for(int i=1;i<=n;i++)
    29         ans=max(ans,f[i][i+n-1]);
    30     printf("%d",ans);
    31     return 0;
    32 }

    总结一些数论小板子:

    • 快速幂
    1 ll ksm(ll a,ll b,int mod){
    2     ll ret=1;
    3     while(b){
    4         if(b&1) ret=ret*a%mod;  // b&1 表示 b在二进制下最后一位是1
    5         a=a*a%mod;
    6         b>>=1;
    7     }
    8     return ret;
    9 }
    • 裴蜀定理

    问题: 给出n个数(A1...An) 现求一组整数序列(X1...Xn) 使得 S=A1X1+...AnXn>0, 且S的值最小

    解法: ax+by=c,xN+,yN成立的充要条件是 gcd(a,b) | c 

     1 #include<cstdio>
     2 using namespace std;
     3 int ans;
     4 int gcd(int a,int b){
     5     return !b ?a : gcd(b,a%b);
     6 }
     7 int main()
     8 {
     9     int n,m;
    10     scanf("%d",&n);
    11     for(int i=1;i<=n;i++){
    12         scanf("%d",&m);
    13         m=(m>0)?m:-m;       //数据中有负数,要将其变为正数再求gcd
    14         ans=gcd(ans,m);
    15     }
    16     printf("%d
    ", ans);
    17     return 0;
    18 }

     


      无线通讯网【最小生成树】

    题意:

    他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。

    收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

    思路:

    做本题首先应该知道一共有p个点就是树有p-1条边,有s个卫星电话就是不用连接最大的s-1条边。

    求树中前(p-s)条边里的最大边即可。

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 #define re register
     5 #define in inline
     6 #define ll long long
     7 #define N 250010
     8 using namespace std;
     9 in int read(){
    10     int x=0,f=1; char c=getchar();
    11     while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    13     return x*f;
    14 }
    15 
    16 struct node{
    17     int u,v;
    18     double w;
    19 }edge[N];
    20 int s,p,cnt,tot,fa[N],px[N],py[N];
    21 
    22 int getfather(int x){
    23     if(x==fa[x]) return x;
    24     return fa[x]=getfather(fa[x]);
    25 }
    26 
    27 in bool cmp(node x,node y){
    28     return x.w<y.w;
    29 }
    30 
    31 double solve(int i,int j){
    32     double dis=(double)sqrt((px[i]-px[j])*(px[i]-px[j])+(py[i]-py[j])*(py[i]-py[j]));
    33     return dis;
    34 }
    35 
    36 void kruskal(){
    37     sort(edge+1,edge+1+cnt,cmp);
    38     for(re int i=1;i<=cnt;i++){
    39         int x=getfather(edge[i].u);
    40         int y=getfather(edge[i].v);
    41         if(x==y) continue;
    42         fa[y]=x;
    43         if(++tot==p-s){
    44             printf("%.2lf",edge[i].w);
    45             exit(0);
    46         }
    47     }
    48 }
    49 
    50 int main()
    51 {
    52     s=read(),p=read();
    53     for(re int i=1;i<=p;i++) px[i]=read(),py[i]=read();
    54     for(re int i=1;i<=p;i++) fa[i]=i;
    55     for(re int i=1;i<p;i++)
    56         for(re int j=i+1;j<=p;j++){
    57             double dis=solve(i,j);
    58             cnt++;
    59             edge[cnt].u=i,edge[cnt].v=j,edge[cnt].w=dis;
    60         }
    61     kruskal();
    62     return 0;
    63 }
  • 相关阅读:
    iOS删除Scene
    IOS如何解决强引用中的循环引用
    IOS中performSelector线程使用
    IOS中的类方法和实例方法
    Mac系统上安装Java的JDK并配置环境变量
    Java开发基本环境知识
    SVN上传工具Cornerstone的简单使用
    05--学习PHP面向对象--静态成员与常量成员
    04--学习PHP面向对象--访问权限修饰符
    03--学习PHP面向对象--$this
  • 原文地址:https://www.cnblogs.com/RR-Jin/p/11756302.html
Copyright © 2020-2023  润新知