牛客算法周周练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; }
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; }
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; }
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<<">"; } }