算法周周练7
(EAD)
E:数字比较
思路:x,y范围都是1e9,而且还是计算次方,直接计算肯定是不行的。根据高中数学知识,可以两边同时取对数,就化成了比较ylogx和xlogy的大小。
代码:
///ylogx和xlogy #include<bits/stdc++.h> typedef long long ll; using namespace std; int main(){ ll x,y; cin>>x>>y; ll a=y*log(x); ll b=x*log(y); if(a==b) puts("="); else if(a>b) puts(">"); else puts("<"); return 0; }
A:收集纸片
思路:因为数据范围很小所以可以考虑暴力枚举出收集纸片的顺序,取min即可。可以用dfs,C++里STL的next_permutation函数,状压DP应该也可。
代码:
#include<bits/stdc++.h> using namespace std; typedef pair<int,int>PII; PII a[20]; int b[20]; int main(){ int t;cin>>t; while(t--){ int n,m,sx,sy; cin>>n>>m; cin>>sx>>sy; int k;cin>>k; for(int i=1;i<=k;i++){ int x,y; cin>>x>>y; a[i]={x,y}; b[i]=i; } int res=0x3f3f3f3f; do{ int lx=sx,ly=sy; int sum=0; for(int i=1;i<=k;i++){ sum+=abs(lx-a[b[i]].first)+abs(ly-a[b[i]].second); lx=a[b[i]].first,ly=a[b[i]].second; } res=min(res,sum+abs(lx-sx)+abs(ly-sy)); }while(next_permutation(b+1,b+1+k)); printf("The shortest path has length %d\n",res); } return 0; }
D:华华和月月逛公园
题意:给定一个无向连通图,求走过所有点不需要走过的边的数量。
思路:无向图里保持连通必须要经过的边叫做桥,用总边数减去桥的个数就是答案。所以问题就转化成了如何求无向图连通图里桥的个数。
桥的概念,桥是指的无向图里的一条无向边,删去该边后连通图将不再连通。
对每个点定义两个时间戳
dfn[u]遍历到u的时间
low[u]表示从u开始走 所能遍历到的最小时间戳
如何找到桥:x->y的祖先节点 x->y不是桥
桥<==>dfn[x]<low[y]
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+100,maxm=maxn*6; int h[maxn],dfn[maxn],low[maxn]; int e[maxm],ne[maxm],idx; int timetmp=0; int res=0; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void tarjan(int u,int fa){ low[u]=dfn[u]=++timetmp; for(int i=h[u];~i;i=ne[i]){ int j=e[i]; if(j==fa) continue; if(!dfn[j]){ tarjan(j,u); low[u]=min(low[u],low[j]); if(low[j]>dfn[u]) res++; } else low[u]=min(low[u],dfn[j]); } } int main(){ int n,m; cin>>n>>m; memset(h,-1,sizeof h); for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; add(x,y);add(y,x); } tarjan(1,0); cout<<m-res<<endl; return 0; }