t1
三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口。(来自取名力为0的出题人)
具体来说,城中有无穷多个路口,每个路口有唯一的一个正整数标号。除了1号路口外,每个路口都连出正好3条道路通向另外3个路口:编号为x(x>1)的路口连出3条道路通向编号为x*2,x*2+1和x/2(向下取整)的3个路口。1号路口只连出两条道路,分别连向2号和3号路口。
所有道路都是可以双向通行的,并且长度都为1。现在,有n个问题:从路口x到路口y的最短路长度是多少?
找最近公共祖先,加深度。
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
const int M=11000;
int n,ans,x,y;
int main(){
scanf("%d",&n);
while(n--){
scanf("%d%d",&x,&y);
ans=0;
int dx=log2(x),dy=log2(y);
if(dx<dy) swap(dx,dy),swap(x,y);
while(dx>dy)
x>>=1,dx--,ans++;
while(x!=y)
x>>=1,y>>=1,ans+=2;
printf("%d\n",ans);
}
}
t3
你承包了一片香子兰花田。现在到了收获的季节,你需要把种下的香子兰全部收获起来,到花店卖掉并取得新的种子,再向田里播种下一季的香子兰。
你的花田一共由n-2片花田组成,编号从1到n-2。算上你的家和花店,一共有n个地点,其中你的家编号为0,花店编号为n-1。即,家、花田、花店都属于地点,且它们都有一个唯一的0~n-1的编号。有m条双向道路连接这些地点。保证所有地点间都是直接或间接连通的。
你需要从家里出发,经过所有的花田进行收获,再到达花店,再从花店出发经过所有花田进行播种,最后重新回到家中。当你经过一片花田的时候,你可以选择收获、播种或者什么事都不做,也就是说你经过一片未收割的花田时可以不立即收割它,播种亦然。然而,播种必须发生在你完成了所有收获并到花店交货之后。在完成最后一个花田的收获后,你必须在到达花店后才能开始播种。也就是说,在你没有收获完所有花田并到花店交货前,即使你已经经过了花店,你也不能进行播种。(啰嗦了这么多但愿讲明白了)
然而还有一个问题。在收割完花朵后,花田会变得光秃秃的,此时土地里的水分会迅速蒸发。考虑到这个问题,更早被收割的花田也理应更早地被播种。具体来说,你必须保证前个被收割的花田也是前个被播种的,其中符号表示向下取整。你不需要保证这些花田收割和播种的顺序完全一致,而只需要保证前名的集合不变即可。
现在,你需要求出完成上述一系列动作走过的最短路程。
一个状压dp题
dp[i][j]表示从家走,j状态,最后到i的最短路
f[i][j]表示走到花店,从谁开始的最小值
预处理处dp[i][j],f[i][j]
dp[i][j]+f[k][j^1<
#include <cstdio>
#include <cstring>
#include <iostream>
#define inf 707406378
#define N 24
using namespace std;
int n1,n2,e[24],cnt[1050000],n,m,dis[24][24],f[2][24][1050000],ans;
int main(){
freopen("vanilla_big.in","r",stdin);
e[0]=1;
//freopen("vanilla.out","w",stdout);
for(int i=1;i<=22;i++) e[i]=e[i-1]<<1;
for(int i=0;i<e[20];i++)
for(int j=i;j;j>>=1) cnt[i]+=j&1;
scanf("%d%d",&n,&m);
n1=(n-2)/2;
n2=n-2-n1;
memset(dis,127/3,sizeof dis);
//printf("%d",dis[1][1]);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
++x,++y;
dis[y][x]=dis[x][y]=min(dis[x][y],z);
}
for(int i=1;i<=n;i++) dis[i][i]=0;
for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
if(i!=j&&j!=k&&k!=i)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
if (n == 3)
{
printf("%d\n", (dis[1][2]+dis[2][3])*2);
return 0;
}
memset(f,127/3,sizeof f);
for(int q=0;q<=1;q++)
{
for(int i=2;i<n;i++)
f[q][i][e[i-2]]=dis[(q==0)?1:n][i];
for(int s=1;s<e[n-2];s++)
if(cnt[s]<=n1)
for(int i=2;i<n;i++)
if(f[q][i][s]<inf)
for(int j=2;j<n;j++)
f[q][j][s|e[j-2]]=min(f[q][j][s|e[j-2]],f[q][i][s]+dis[i][j]);
}
ans=inf;
for(int sta=0;sta<e[n-2];sta++)
if(cnt[sta]==n1){
int tmp=inf;
for(int i=2;i<n;i++)
if(e[i-2]&sta)
for(int j=2;j<n;j++)
if(!(e[j-2]&sta))
tmp=min(tmp,f[0][i][sta]+dis[i][j]+f[1][j][e[n-2]-1-sta]);
for(int i=2;i<n;i++)
if(e[i-2]&sta)
for(int j=2;j<n;j++)
if(!(e[j-2]&sta))
ans=min(ans,tmp+f[1][i][sta]+dis[i][j]+f[0][j][e[n-2]-1-sta]);
}
printf("%d",ans);
}