• 20170925“切题如切菜杯”水题模拟赛 第二弹


    T1:短

     给出一张有n个点和m条双向边的图,要求求出1到n的次短路的长度。一条边可以多次通过。

    输入格式:

    第一行为两个整数n和m。接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个点和他的长度。

    输出格式:

    一个整数,表示次短路的长度。

    样例输入

    样例输出

    4 4
    1 2 100
    2 4 200
    2 3 250
    3 4 100

    450

    样例解释:

    最短:1->2->4。

    次短:1->2->3->4。

    数据范围:

    对于 100%的数据:1<=n、vi<=50001<=m<=100000

    solution: 裸的不能再裸的最短路,但用spfa会被卡,就上dij代码

    #include<cstdio>  
    #include<algorithm>  
    #include<queue>  
    #include<vector>  
    using namespace std;  
    const int maxn = 5000+100;  
    const int inf = 0x7fffffff;  
    typedef pair<int,int> P;  
    struct edge{  
        int to,cost;  
    };  
    vector<edge> G[maxn];  
    int n,m,ans;  
    int dis1[maxn],disn[maxn];  
    void Dijkstra(int src,int dis[]) 
    {  
        priority_queue< P,vector<P>,greater<P> >que;  
        dis[src]=0;  
        que.push(P(dis[src],src));  
        while(!que.empty()){  
            P p=que.top();  
            que.pop();  
            int u=p.second,d=p.first;  
            if(d>dis[u]) continue;  
            for(int i=0;i<G[u].size();i++){  
                edge e=G[u][i];  
                if(e.cost+d<dis[e.to]){  
                    dis[e.to]=d+e.cost;  
                    que.push(P(dis[e.to],e.to));  
                }  
            }  
        }  
    }  
    void solve()  
    {  
        fill(dis1+1,dis1+1+n,inf);  
        fill(disn+1,disn+1+n,inf);  
        Dijkstra(1,dis1);  
        Dijkstra(n,disn);  
        ans=0x7fffffff;  
        for(int i=1;i<=n;i++)   
        for(int j=0;j<G[i].size();j++){  
            int v=G[i][j].to,d=G[i][j].cost;  
            if(dis1[i]+d+disn[v]>dis1[n]){  
                ans=min( ans , dis1[i]+ d + disn[v] );  
            }  
        }  
    }  
    int main()  
    {  
        freopen("short.in","r",stdin);
        freopen("short.out","w",stdout); 
        scanf("%d%d",&n,&m);  
        int u,v,w;  
        edge e;  
        for(int i=1;i<=m;i++){  
            scanf("%d%d%d",&u,&v,&w);  
            e.to=v,e.cost=w;  
            G[u].push_back(e);  
            e.to=u;  
            G[v].push_back(e);  
        }  
        solve();  
        printf("%d
    ",ans);  
        return 0;  
    }  

    T2:你的四边形已如风中残烛

      LGL有一根长为n的木板。现在他想要把它砍成四段长度为整数的木板来做一个四边形,请问他有多少种不同的砍法?注意:四段长度为1、1、2、1和四段长度为1、2、1、1算两种砍法。

    输入格式:

    第一行为一个整数 n,表示木板的长度。

    输出格式:

    一个整数,不同的砍法数量。

    样例输入

    样例输出

    6

    6

    样例解释:

    11221212,1221,2112,2121,2211。

    数据范围:

    对于100%的数据:1<=n<=2500

    solution:

    dp[i][j]表示长度为i时分成j段的方案数,随便转移。

    这是正解,当然因为本题比较特殊,附上两个暴力代码。

    正常暴力

    #include<cstdio>
    using namespace std;
    int main()
    {
        freopen("quad.in","r",stdin);
        freopen("quad.out","w",stdout);
        long long t,n,sum=0;
        scanf("%lld",&n);
        for(long long i=1;i<=n-3;i++)
        for(long long j=1;j<n-i;j++)
        for(long long k=1;k<n-i-j;k++)
        {
            long long m=n-i-j-k;
            if((i+j+k>m)&&(i+k+m>j)&&(i+m+j>k)&&(k+m+j>i))
            sum++;
        }    
        printf("%lld
    ",sum);
    }

    优化暴力(from巨神lzb

    #include<cstdio>
    using namespace std;
    int main(){
        freopen("bll.out","w",stdout);
        for(int n=0;n<=2500;n++){
            long long ans=0;
            for(int i=1;i<=n/4;i++)
                for(int j=i;j<=(n-i)/3;j++)
                    for(int k=j;k<=(n-i-j)/2;k++)if(n-i-j-k<i+j+k){
                        if(i==j&&j==k&&k==n-i-j-k)ans++;
                        else if((i==j&&j==k)||(j==k&&k==n-i-j-k))ans+=4;
                        else if(i==j&&k==n-i-j-k)ans+=6;
                        else if(i==j||k==n-i-j-k||j==k)ans+=12;
                        else ans+=24;
                    }
            printf("%lld,",ans);
    } 
    } 

    正解

    #include <cstdio>
    #include <cstring>
     
    int n,mid;
    int dp[2501][5];
    
    int getint()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-f;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
     
    int min(int a,int b)
    {
        return a<b?a:b;
    }
     
    int main()
    {
        freopen("quad.in","r",stdin);
        freopen("quad.out","w",stdout);
        n=getint();
        mid=(n-1)>>1;
        dp[0][0]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=4;j++)
            {
                for(int k=1;k<=min(mid,i);k++) dp[i][j]+=dp[i-k][j-1];
            }
        }
        printf("%d",dp[n][4]);
        return 0;
    }

    T3:生命不息刷题不止

     YYH有n道题要做。但是由于他上课做某些事,导致他一题都不会做,只好请LGL代打。LGL为了买自己心爱的坦克,他做第i题要收两笔钱:一笔在YYH叫他做题当天收,另外一笔在叫他做题的第二天收。YYH每天结束的时候都会把剩下的所有钱花光,然后再从父亲LRB处得到m元零花钱用来请LGL做题(也就是说,第一天的时候YYH是没有钱请LGL做题的,每一天用来请LGL做题所用的钱都是前一天LRB给的)。而且,YYH做的题目难度是循序渐进的:就算强如LGL,在做第i题之前也要先把第1到i-1题全部做完。请问YYH将所有题目做完并且把所有钱都付给LGL的最小天数。

    输入格式:

    第一行为两个整数m、n,接下来的n行每一行都有两个数aibi,分别表示LGL做第i题所收的两笔钱。

    输出格式:

    一个整数,表示最小天数。

    样例输入

    样例输出

    100 5
    40 20
    60 20
    30 50
    30 50
    40 40

    6

    样例解释:

    第二天做1、2两题,第三天做3、4两题,第五天做5。在第六天的时候所有钱都付完。

    数据范围:

    对于100%的数据:1<=n<=300,1<=aibi<=m<=1000。

    solution:dp[i][j]表示前i天做了j题后该天可能剩下的最多的钱的数量。那么dp[i][j]可以转移到dp[i][j+1]dp[i][j+2]……只要满足剩下的钱不少于0并且下个月的钱够还即可。同时可以算出dp[i+1][j+1]dp[i+1][j+2]……最后输出满足dp[i][m]存在值的最小i。

    #include <cstdio>
    #include <cstring>
    #define INF 0x3f3f3f3f
    int n,m,t1,t2;
    int a[301],b[301];
    int dp[501][301];
    int getint()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-f;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
     
    int max(int a,int b)
    {
        return a>b?a:b;
    }
     
    int main()
    {
        freopen("solve.in","r",stdin);
        freopen("solve.out","w",stdout);
        n=getint(),m=getint();
        for(int i=1;i<=m;i++) a[i]=getint(),b[i]=getint();
        memset(dp,INF,sizeof(dp));
        dp[2][0]=n;
        int i=2;
        while(dp[i][m]==INF)
        {
            for(int j=m;j>=0;j--)
            {
                if(dp[i][j]!=INF)
                {
                    int k=j+1;
                    t1=dp[i][j],t2=dp[i+1][j]=n;
                    while(t1>=a[k]&&t2>=b[k])
                    {
                        t1-=a[k];
                        t2-=b[k];
                        dp[i][k]=(dp[i][k]==INF?t1:max(dp[i][k],t1));
                        dp[i+1][k]=(dp[i+1][k]==INF?t2:max(dp[i+1][k],t2));
                        k++;
                    }
                }
            }
            i++;
        }
        printf("%d",i);
        return 0;
    }

    T4:个人卫生综合征

    每天BBS都要从家里经过城市中的一段路到学校刷五三。城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口aibi且有一定的时间花费viBBS家编号为1,学校编号为n。今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0。现在他问你改变道路长度之后他到学校的最小时间花费是多少?

    输入格式:

    第一行为三个整数n、m、k,接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个路口和通过其所用的时间。

    输出格式:

    一个整数,表示BBS到学校的最小时间花费。

    样例输入

    样例输出

    4 4 1
    1 2 10
    2 4 10
    1 3 1
    3 4 100

    1

    样例解释:

    更新3->4的道路,最短路线为1->3->4,用时为1+0=1。

    数据范围:

    对于100%的数据:1<=n<=10000,1<=m<=50000,1<=k<=201<=vi<=1000000

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #define INF 0x3f3f3f3f
     
    struct path
    {
        int to,v;
    };
    struct node
    {
        int num,v;
        bool operator <(const node &b) const
        {
           return v>b.v;
        }
    };
    std::vector<path> g[10001];
    std::priority_queue<node> q;
    int m,n,k,ans;
    int dist[10001][21];
    bool vis[10001][21];
    
    int getint()
    {
        int x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') f=-f;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
     
    int min(int a,int b)
    {
        return a<b?a:b;
    }
     
    void dij()
    {
        node now;
        memset(dist,INF,sizeof(dist));
        memset(vis,false,sizeof(vis));
        dist[1][0]=0;
        q.push((node){1,0});
        while(!q.empty())
        {
            now=q.top();
            q.pop();
            int t1=now.num%(n+1),t2=now.num/(n+1);
            vis[t1][t2]=true;
            for(int i=0;i<int(g[t1].size());i++)
            {
                path t=g[t1][i];
                if((!vis[t.to][t2])&&dist[t.to][t2]>dist[t1][t2]+t.v)
                {
                    dist[t.to][t2]=dist[t1][t2]+t.v;
                    q.push((node){t2*(n+1)+t.to,dist[t.to][t2]});
                }
                if((!vis[t.to][t2+1])&&t2<k&&dist[t.to][t2+1]>dist[t1][t2])
                {
                    dist[t.to][t2+1]=dist[t1][t2];
                    q.push((node){(t2+1)*(n+1)+t.to,dist[t.to][t2+1]});
                }
            }
        }
    }
     
    int main()
    {
        freopen("school.in","r",stdin);
        freopen("school.out","w",stdout);
        n=getint(),m=getint(),k=getint();
        for(int i=1;i<=m;i++)
        {
            int a=getint(),b=getint(),v=getint();
            g[a].push_back((path){b,v});
            g[b].push_back((path){a,v});
        }
        dij();
        ans=INF;
        for(int i=0;i<=k;i++) ans=min(ans,dist[n][i]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    如何判断哪个方法调用了相同的事件?
    Windows Update问题
    Android学习笔记
    关于官方Reachability Demo理解
    poj 1797 Heavy Transportation
    poj 3013 Big Christmas Tree
    poj 1062 昂贵的聘礼
    poj 3615 Cow Hurdles(floyd)
    CF Planets(STL+ 最短路)
    poj 3026 Borg Maze
  • 原文地址:https://www.cnblogs.com/qizhengquan/p/7592837.html
Copyright © 2020-2023  润新知