zoukankan      html  css  js  c++  java
  • 暑假的学习

    刷题时,刷到了阮一峰的博客,看了看感觉是个比较有想法的人,有兴趣可以百度一下

    先记录下今天的学习吧

    给一张图,从1点出发,要求是一次走完后,再求出这次中从1点到达各个点的总时间,其中每个点都有deadlinetime

    先是对这个图跑一遍floyd,让每个点都预处理一下,然后进行深搜,深搜的时候要注意剪枝

    最优性剪枝和可行性剪枝

    #include<bits/stdc++.h>
    using namespace std;
    int str[35][35];
    int n,ans,dd[35];
    int vis[35];
    int inf=0x3f3f3f3f;
    void floyd()
    {
        for(int k=1;k<=n;k++)
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=n;j++)
                str[i][j]=min(str[i][j],str[i][k]+str[k][j]);
            }
        }
    }
    void dfs(int s,int time,int total,int cnt)//time为到达某个点的时间//total为总时间,cnt剩余点数 
    {
        if(cnt==0)
        {
            ans=min(ans,total);
            return;
        }
         if (total+cnt*time >= ans) //后面的点的time肯定是越来越大的,假设都为time,最优性剪枝 
             return;
         
        
        for(int i=2;i<=n;i++)//这个循环和下面要分开写 ,这个是判断当前点s 的可行性剪枝 
        if(!vis[i]&&time+str[s][i]>dd[i]) return;//s到其他点有超时的,那么再从这点出发后不管怎样都可定超时 
        for(int i=2;i<=n;i++)
        {
            if(!vis[i])
            {
                vis[i]=1;
                dfs(i, time+str[s][i] , total+time+str[s][i], cnt-1);
                vis[i]=0;
            }
        }
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    scanf("%d",&str[i][j]);
            for(int i=2;i<=n;i++) scanf("%d",&dd[i]);
            
            floyd();
            memset(vis,0,sizeof(vis));
            ans=inf;
            dfs(1,0,0,n-1);
            if(ans == inf )printf("-1
    ");
            else printf("%d
    ",ans);    
        }
    }

    双向bfs

    HDU - 3085 

    题意:erriye 梦见女友被困在迷宫里了,现在 erriye 需要去解救他的的女友 给出他女友和他的位置

    题意:迷宫里有两个ghost,每秒钟会分生出多个ghost占据在他2步之内的所有格子

    little erriye 每秒可以移动3步,grilfriend每秒可以移动一步

    ghost、erriye、grilfriend都只能上下左右移动(且人不能穿透墙壁,鬼魂可以)

    题意:人一旦与鬼魂占据同一格子,则被杀死

    题意:问:little erriye 最少需要多久才能解救其女友?(如果解救失败,输出-1)

    #include<bits/stdc++.h>
    using namespace std;
    
    int dx[]={0,0,1,-1};
    int dy[]={1,-1,0,0};
    
    char str[802][802];
    int vis[2][802][802];//标记路径 
    int n,m,step;
    struct node{
        int x,y;
    }ss,ee,z[2];
    queue<node>q[2];
    void init()
    {
        int cnt=0;
        cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            scanf("%s",str[i]);
            for(int j=0;j<m;j++)
            {
                if(str[i][j]=='M') ss.x=i,ss.y=j;
                else if(str[i][j]=='G') ee.x=i,ee.y=j;
                else if(str[i][j]=='Z') z[cnt].x=i,z[cnt++].y=j;
            }
        }
    }
    int judge(node b)
    {
        if(b.x<0||b.y<0||b.x>=n||b.y>=m||str[b.x][b.y]=='X')
        return 0;
        if(abs(b.x-z[0].x)+abs(b.y-z[0].y)<=2*step)//判断是否撞鬼
        return 0;
        if(abs(b.x-z[1].x)+abs(b.y-z[1].y)<=2*step)
        return 0;
        return 1;
    }
    int bfs(int w)
    {
        node now,next;
        int sum;
        sum=q[w].size();
        while(sum--)
        {
            now=q[w].front();
            q[w].pop();
            if(judge(now)==1)
            {
                for(int i=0;i<4;i++)
                {
                    next.x=now.x+dx[i];
                    next.y=now.y+dy[i];
                    
                    if(judge(next)==1&&vis[w][next.x][next.y]==0)
                    {
                        if(vis[w^1][next.x][next.y]==1)//解救成功条件是这条路是另一个人走过的 
                        return 1;
                        vis[w][next.x][next.y] = 1;
                        q[w].push(next);
                    }
                }
            }
        }
        return -1;
    }
    int solve()
    {
        while(!q[0].empty())q[0].pop();
        while(!q[1].empty()) q[1].pop();
        
        q[0].push(ss);
        q[1].push(ee);
        
        memset(vis,0,sizeof(vis));
        vis[0][ss.x][ss.y]=vis[1][ee.x][ee.y]=1;
        step=0;
        while((!q[0].empty())||(!q[1].empty()))
        {
            step++;
            if(bfs(0)==1) return step;
            if(bfs(0)==1) return step;
            if(bfs(0)==1) return step;
            if(bfs(1)==1) return step;
        }
        return -1;
    }
    int main()
    {
        int tt;
        cin>>tt;
        while(tt--)
        {
            init();
            cout<<solve()<<endl;
        }
        return 0;
    }

     hdu6383

    http://acm.hdu.edu.cn/showproblem.php?pid=6383

    题目大意:给你一堆数字,可以随便找两个,一个+1,一个-2,使最后形成的数列最大值和最小值相差为1,求最小值的最大值

    #include<bits/stdc++.h>
    using namespace std;
    long long a[10000020];
    int main()
    {
        long long t;
        scanf("%lld",&t);
        while(t--)
        {
            long long n;
            scanf("%lld",&n);
            long long l=0x3f3f3f3f,r=-1;
            for(int i=0;i<n;i++) {
                scanf("%lld",&a[i]);
                l=min(l,a[i]);
                r=max(r,a[i]);
            }
            long long mid=0,ans=-1;
            while(l<=r)//注意不要l<r会死循环 
            {
                mid=(l+r)>>1;
                long long up=0,down=0;
                for(int i=0;i<n;i++)
                {
                    if(a[i]<mid)up+=mid-a[i];
                    else if(a[i]>mid) down+=(a[i]-mid)>>1; 
                }
                if(up<=down)//降得情况要大于升的情况,因为降我可以+1,-2,让后-2,+1,这样两个数就都减一,然而升的话只能+1+1的升 
                {
                    l=mid+1;
                    ans=max(ans,mid);
                }
                else r=mid-1;
            }
            printf("%lld
    ",ans);
        }
    }

    poj1064

    http://poj.org/problem?id=1064

    经典的割绳子问题

    n段绳子,我要m段,问能割的最长长度

    #include<iostream>
    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    double a[10010];
    const double eps=0.00000001;
    int n,m;
    int judge(double x)
    {
        int ans=0;
        for(int i=0;i<n;i++)
        ans+=(int)(a[i]/x);
        if(ans>=m) return 1;
        else return 0;
    } 
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=0;i<n;i++) scanf("%lf",&a[i]);
            double l=0,r=100001;
            double t=0;
            while(r-l>=eps)
            {
                double mid=(l+r)/2;
                if(judge(mid))l=mid;
                else r=mid;
            }
            printf("%.2lf
    ",floor(r*100)/100);
        }
    }

    hdu3746

    给一个字符串,看缺几个可以构成循环

    kmp算法循环节裸题,先上模板

    void getnext()
    {
        int i=0,j=-1;
        next[0]=-1;
        while(i<tlen)
        {
            if(j==-1||t[i]==t[j])
            next[++i]=++j;
            else
            j=next[j];
        }
        
     } 
     int kmp_index()//统计出现位置
     {
         int i=0,j=0;
         getnext();
         while(i<slen && j<tlen)
         {
             if(j==-1 ||s[i]==t[j])//匹配成功则往下找 
             i++;j++;
             else //否则把t字符串往前移动 
             j=next[j];
         }
         if(j==tlen) return i-tlen;
         else return -1;
     }
     int kmp_count()//统计出现次数
     {
         int ans=0,i=0,j=0;
         while(i<slen)
         {
             if(j==-1||s[i]==t[j])//同上 
             i++,j++;
             else
             j=next[j];
             
             if(j==tlen)//判断是否有了 
             {
                 ans++;
                 j=next[j];
             }
         }
         return ans; 
     }

    代码

    #include<iostream>
    #include<string.h>
    using namespace std;
    int nextt[1000005];
    char a[100002];
    void getnext()
    {
        int i=0,j=-1;
        nextt[0]=-1;
        int t=strlen(a);
        while(i<t)
        {
            if(j==-1 || a[i]==a[j])
            nextt[++i]=++j;
            else j=nextt[j];
        }
    }
    int main()
    {
        int n;
        
        scanf("%d",&n);
        while(n--)
        {
            
            scanf("%s",a);
            getnext();
            int t=strlen(a);
            if(t%(t-nextt[t])==0&&nextt[t]!=0) printf("0
    ");
            else
            printf("%d
    ",(t-nextt[t])-t%(t-nextt[t]));//该字符串长度减去next[末尾]为循环节长度 
        }
        
    }

    codeforces

    http://codeforces.com/contest/1008/problem/D

    给一个长方体,判断是否可以刚好由几个相同的小长方体填满

    题解https://blog.csdn.net/weixin_42165981/article/details/81212814

    https://blog.csdn.net/codeswarrior/article/details/81146331

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5+10;
    ll C(int n,int m){//求组合数 
        ll ans = 1;
        for(int i = 1; i <= m; i++){
            ans = ans * (n-i+1) / i;
        }
        return ans;
    }
    bool check(int a,int b,int c){//如果111 
        if((a & 1) && (b & 2) && (c & 4))
            return true;
        if((a & 1) && (c & 2) && (b & 4))
            return true;
        if((b & 1) && (a & 2) && (c & 4))
            return true;
        if((b & 1) && (c & 2) && (a & 4))
            return true;
        if((c & 1) && (a & 2) && (b & 4))
            return true;
        if((c & 1) && (b & 2) && (a & 4))
            return true;
        return false;
    }
    int gcd(int a,int b){
        if(b == 0)
            return a;
        return gcd(b,a%b);
    }
    int cnt[10],use[10];
    int fac[maxn];
    int main(){
        //????????????
        for(int i = 1; i < maxn; i++){//通过打表来记录每个数的因子个数 
            for(int j = i; j < maxn; j += i){
                fac[j]++;
            }
        }
        int t,x,y,z;
        ll ans;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d",&x,&y,&z);
            int xy = gcd(x,y);
            int yz = gcd(y,z);
            int xz = gcd(x,z);
            int xyz = gcd(xy,z);
            //容斥原理 
            cnt[7] = fac[xyz];//111
            cnt[6] = fac[yz] - fac[xyz];//110
            cnt[5] = fac[xz] - fac[xyz];//101
            cnt[4] = fac[z] - fac[xz] - fac[yz] + fac[xyz];//100
            cnt[3] = fac[xy] - fac[xyz];//011
            cnt[2] = fac[y] - fac[xy] - fac[yz] + fac[xyz];//010
            cnt[1] = fac[x] - fac[xy] - fac[xz] + fac[xyz];//001
            ans = 0;
            for(int a = 1; a < 8; a++){
                for(int b = a; b < 8; b++){
                    for(int c = b; c < 8; c++){
                        if(check(a,b,c)){
                            memset(use,0,sizeof(use));
                            use[a]++;
                            use[b]++;
                            use[c]++;//???????????????
                            ll tmp = 1;
                            for(int i = 1; i < 8; i++){// 
                                if(use[i])
                                    tmp *= C(cnt[i]+use[i]-1,use[i]);
                            }
                            if(tmp > 0)
                                ans += tmp;
                        }
                    }
                }
            }
            cout<<ans<<endl;
        }
        return 0;
    }

    http://codeforces.com/contest/1008/problem/C

    题意给n个数,移动位置后算出最大的数(移动后的数字比以前大的个数)

    #include<bits/stdc++.h>
    using namespace std;
    int a[100002],b[100002];
    int main()
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++) 
        cin>>a[i];
        sort(a,a+n);
        int k=0;
        int ans=0;
        for(int i=0;i<n;i++)
        {
            while(k<=n&&a[k]<=a[i])//找出第一个比第i个数大的
            k++;
            if(k<=n) ans++,k++;
        }
        cout<<ans<<endl;
        
        return 0;
    }

    http://codeforces.com/contest/1008/problem/B

    题意:给了n个矩形的长和宽,可以翻转每一个矩形,也就是交换长和宽,让矩形的长或者宽形成非递增排列。

    #include<bits/stdc++.h>
    using namespace std;
    long long a[100002],b[100002],ans[100002];
    int main()
    {
        int n;
        cin>>n;
        for(int i=0;i<n;i++)
        cin>>a[i]>>b[i];
        
        ans[0]=max(a[0],b[0]);
        int k=1;
        for(int i=1;i<n;i++)
        {
            int t1=max(a[i],b[i]);
            int t2=min(a[i],b[i]);
            if(ans[i-1]>=t1) ans[i]=t1;
            else if(ans[i-1]>=t2) ans[i]=t2;
            else if(ans[i-1]<t2){
                //cout<<i<<" "<<
                cout<<"NO"<<endl;
                return 0;
            }
        }
        cout<<"YES"<<endl;
        return 0;
    }

    http://codeforces.com/contest/1011/problem/B

    题目大意:n个人m个食物,每个食物都有种类,每个人只能吃一种食物(无论哪一种),求最多能活多少天。

    #include<bits/stdc++.h>
    using namespace std;
    int a[105],b[105];
    int main()
    {
        int m,n;
        cin>>m>>n;
        memset(b,0,sizeof(b));
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            b[a[i]]++;
        }
        //for(int i=0;i<10;i++) cout<<b[i]<<endl;
        if(m>n)
        cout<<"0"<<endl;
        else
        {
            int ans=1;
            for(int i=2;i<=100;i++)
            {
                int t=0;
                for(int j=1;j<=100;j++)
                {
                    t+=b[j]/i;
                    //cout<<t<<" ";
                    if(t>=m){
                        ans=max(ans,i);
                        break;
                    }
                }
                
            }
            cout<<ans<<endl;
        }
        return 0;
    }

    http://codeforces.com/contest/1011/problem/C

    给你飞机初始重量,飞机要在所有机场起飞降落。一开始会携带一定重量的汽油,然后每次飞的过程会消耗掉相应汽油,而每个机场给的值是1吨汽油能让他飞多少。

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    int a[1005],b[1005];
    const long long eps=0.0000001;
    double jisuan(double x)
    {
        x-=(m+x)/a[0];
        for(int i=1;i<n;i++)
        {
            if(x<0) return -1;
            x-=(m+x)/b[i];
            if(x<0) return -1;
            x-=(m+x)/a[i];
        }
        if(x<0) return -1;
        x-=(m+x)/b[0];
        if(x<0) return -1;
        else if (x>0) return 1;
        else return 0;
    }
    int main()
    {
    
        cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            if(a[i]==1)
            {
                cout<<-1<<endl;
                exit(0);
            }
        }
        for(int i=0;i<n;i++)
        {
            cin>>b[i];
            if(b[i]==1)
            {
                cout<<-1<<endl;
                exit(0);
            }
        }
        double l=1,r=1000000000;
        double t=0;
        while(r-l>=eps)
        {
            t++;
            if(t==62)
            {
                printf("%.7lf",(l+r)/2);
                return 0;
            }
            double m=(l+r)/2;
            if(jisuan(m)<0) l=m;
            else if(jisuan(m)>0) r=m;
        }
        printf("%.7lf",(l+r)/2);
    }

    今天突然有些新的想法,想要说些什么却不知道从何说起,有一种莫名的兴奋和激动,或许是觉得要想改变自己。

    我觉得以后没事写点东西还是挺好的,记录下自己的思想的转变,还有,要学会独立思考,这我觉得很重要

  • 相关阅读:
    我爱java系列之---【Sublime Text编辑远程Linux服务器上的文件】
    我爱java系列之---【发送请求消息的中间件—okhttp】
    Backpack
    Interleaving String
    Edit Distance
    Longest Common Subsequence
    Jump Game II
    Unique Paths II
    Climbing Stairs
    Triangle -- C3
  • 原文地址:https://www.cnblogs.com/wpbing/p/9483155.html
Copyright © 2011-2022 走看看