牛客算法周周练7-题解

链接:https://ac.nowcoder.com/acm/contest/5927#question

A - 收集纸片

题意:

在二维坐标中有$n$个点需要你依次到达并最后返回起点,求最短路程

思路:

典型的$TSP$旅行商问题,因为$n$最大只有$10$,所以我们可以用$DFS$遍历所有可能的情况,时间复杂度为$O(10!)$

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define inf 0x3f3f3f3f
 using namespace std;
 typedef long long ll;
 int x,y,sx,sy,n,ans;
 int vis[11];
 struct node{
     int x,y;
 }a[11];
 void dfs(int cnt,int num,int dis)
 {
     if(cnt==n){
         ans=min(ans,dis+abs(a[num].x-sx)+abs(a[num].y-sy));
         return;
     }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            int ret=dis+abs(a[num].x-a[i].x)+abs(a[num].y-a[i].y);
            vis[i]=1;
            dfs(cnt+1,i,ret);
            vis[i]=0;
        } 
    }
 }
 int main()
 {
     int t;
     cin>>t;
     while(t--){
         memset(vis,0,sizeof(vis));
         ans=inf;
         cin>>x>>y>>sx>>sy;
        cin>>n;    
        for(int i=1;i<=n;i++)
            cin>>a[i].x>>a[i].y;
        for(int i=1;i<=n;i++){
            vis[i]=1;
            dfs(1,i,abs(a[i].x-sx)+abs(a[i].y-sy));
            vis[i]=0;
        }
        cout<<"The shortest path has length "<<ans<<endl;
     }
     return 0;
 }
View Code

C -  Rabbit的工作(1)

题意:

一共有$n$天,如果连续工作第$i$天需要耗费精力$i$,同时根据安排你也可以休息,不消耗精力,在消耗精力小于等于$k$的情况下,问你最多能工作几天

思路:

定义$dp[i][j][k]$为,过去$i$天,当前已经连续工作$j$天,总计工作$k$天需要消耗的精力

如果选择休息则状态转移方程为$dp[i+1][0][k]=min(dp[i][j][k],dp[i+1][0][k])$

在可以工作的情况下,转态转移方程为$dp[i+1][j+1][k+1]=min(dp[i+1][j+1][k+1],dp[i][j][k]+(j+1))$

最后,因为内存限制,第一维可以用滚动数组节约空间

#include<algorithm>
#include<iostream>
#include<cstring>
#define inf 0x3f3f3f3f
 using namespace std;
 const int N=405;
 int dp[2][N][N];
 string s;
 int main()
 {
     int n,x,ans=0;
     cin>>n>>x;
     dp[0][0][0]=0;
     int now=0;
     cin>>s;
    for(int i=1;i<=n;i++){
        memset(dp[now^1],inf,sizeof(dp[now^1]));
        for(int j=0;j<i;j++){
            for(int k=j;k<i;k++){
                dp[now^1][0][k]=min(dp[now][j][k],dp[now^1][0][k]);
                if(s[i-1]=='1')
                    dp[now^1][j+1][k+1]=min(dp[now][j][k]+j+1,dp[now^1][j+1][k+1]);
            }
        }
        now^=1;
    }
    for(int i=0;i<=n;i++){
        for(int j=i;j<=n;j++){
            if(dp[now][i][j]<=x) 
                ans=max(ans,j);
        }
    }
    cout<<ans;
    return 0;
}
View Code

 D - 华华和月月逛公园

题意:

给一张$n$个点$m$条边的无向图,让你求出非关键边的个数,非关键边的定义为去掉这条边后,依旧可以从$1$号点出发,到达图中所有点

思路:

转换题意后,就是求非桥边的个数,直接套用$tarjan$求桥的模板即可

#include<iostream>
#include<algorithm>
#include<vector>
 using namespace std;
 const int maxn=1e5+10;
 vector<int> a[maxn];
 int ans=0,vis[maxn];
 void dfs(int tim,int fa,int u)
 {
    vis[u]=tim;
     for(int i=0;i<a[u].size();i++){
         int v=a[u][i];
         if(v==fa) continue;
         if(vis[v]){
             ans+=tim+1-vis[v];
             vis[v]=tim+1;
             continue;
         }
         dfs(tim+1,u,v);
     }
 }
 int main()
 {
     int n,m,u,v;
     cin>>n>>m;
     for(int i=1;i<=m;i++){
         cin>>u>>v;
         a[u].push_back(v);
         a[v].push_back(u);
     }
    dfs(1,1,1);
    cout<<ans<<endl;
 }
View Code

 E - 数字比较

题意:

给两个数字$x$与$y$,比较$x^{y}$跟$y^{x}$的大小

思路:

将$x^{y}$跟$y^{x}$化成幂次相同的形式,在比较两数的底数大小即可

#include<algorithm>
#include<iostream>
 using namespace std;
 typedef long long ll;
 int main()
 {
     ll x,y;
     cin>>x>>y;
     if(y>=x){
         if(pow(x,1.0*y/x)>y) cout<<">";
         else if(pow(x,1.0*y/x)==y) cout<<"=";
         else cout<<"<";
     }
    else{
        if(pow(y,1.0*x/y)>x) cout<<"<";
         else if(pow(y,1.0*x/y)==x) cout<<"=";
         else cout<<">";
    }
 }
View Code

 

posted @ 2020-05-28 20:56  overrate_wsj  阅读(158)  评论(0编辑  收藏  举报