暑假的学习

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

先记录下今天的学习吧

给一张图,从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\n");
        else printf("%d\n",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\n",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\n",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\n");
        else
        printf("%d\n",(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);
}

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

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

猜你喜欢

转载自www.cnblogs.com/wpbing/p/9483155.html