刷题#R14

来源:互联网 发布:python 接口 编辑:程序博客网 时间:2024/05/01 08:14

三向城
题目描述
三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口。(来自取名力为0的出题人)
具体来说,城中有无穷多个路口,每个路口有唯一的一个正整数标号。除了1号路口外,每个路口都连出正好3条道路通向另外3个路口:编号为x(x>1)的路口连出3条道路通向编号为x*2,x*2+1和x/2(向下取整)的3个路口。1号路口只连出两条道路,分别连向2号和3号路口。
所有道路都是可以双向通行的,并且长度都为1。现在,有n个问题:从路口x到路口y的最短路长度是多少?

输入格式
第一行包含一个整数n,表示询问数量;
接下来n行,每行包含两个正整数x, y,表示询问从路口x到路口y的最短路长度。

输出格式
输出n行,每行包含一个整数,表示对每次询问的回答。如果对于某个询问不存在从x到y的路径,则输出-1。

样例输入
3
5 7
2 4
1 1

样例输出
4
1
0

样例解释
5号路口到7号路口的路径为:5->2->1->3->7,长度为4;
2号路口到4号路口的路径为:2->4,长度为1;
1号路口到本身的路径长度为0;

数据范围
对30%的数据,x,y≤20;
对60%的数据,x,y≤10^5,n≤10;
对100%的数据,x,y≤10^9,n≤10^4。

香子兰
题目描述
你承包了一片香子兰花田。现在到了收获的季节,你需要把种下的香子兰全部收获起来,到花店卖掉并取得新的种子,再向田里播种下一季的香子兰。
你的花田一共由n-2片花田组成,编号从1到n-2。算上你的家和花店,一共有n个地点,其中你的家编号为0,花店编号为n-1。即,家、花田、花店都属于地点,且它们都有一个唯一的0~n-1的编号。有m条双向道路连接这些地点。保证所有地点间都是直接或间接连通的。
你需要从家里出发,经过所有的花田进行收获,再到达花店,再从花店出发经过所有花田进行播种,最后重新回到家中。当你经过一片花田的时候,你可以选择收获、播种或者什么事都不做,也就是说你经过一片未收割的花田时可以不立即收割它,播种亦然。然而,播种必须发生在你完成了所有收获并到花店交货之后。在完成最后一个花田的收获后,你必须在到达花店后才能开始播种。也就是说,在你没有收获完所有花田并到花店交货前,即使你已经经过了花店,你也不能进行播种。(啰嗦了这么多但愿讲明白了)
然而还有一个问题。在收割完花朵后,花田会变得光秃秃的,此时土地里的水分会迅速蒸发。考虑到这个问题,更早被收割的花田也理应更早地被播种。具体来说,你必须保证前个被收割的花田也是前个被播种的,其中符号表示向下取整。你不需要保证这些花田收割和播种的顺序完全一致,而只需要保证前名的集合不变即可。
现在,你需要求出完成上述一系列动作走过的最短路程。

输入格式
第一行包含两个整数n, m,表示地点总数和道路条数;
接下来m行,每行包含3个整数xi, yi, zi,表示有一条连接编号为xi和yi 的地点,长为zi的道路。

输出格式
一行,包含一个整数,表示最短路程。

样例输入
4 4
0 1 1
1 2 2
2 3 1
1 3 1

样例输出
10

样例解释
从0出发,先走到1收获(距离1),再走到2收获(距离2),再走到3交货(距离1),再走到1播种(距离1),再走到2播种(距离2),再走到1什么都不干(距离2),再走到0(距离1)。总距离为10。前个被收获和播种的花田集合是{1号花田}。

数据范围
对于30%的数据,有n≤8;
另有10%的数据,有m=n-1,且对1≤i≤m,保证xi=i-1,yi=i;
另有20%的数据,有m=n-1,且每个花田至多只与另外两个花田有道路相连;
对于100%的数据,有n≤20,m≤400,0≤xi, yi≤n-1,xi≠yi,0≤zi≤10000。

T1
这是一个二叉树,向上翻就行。
T3
状态压缩DP
Floyd预处理两两之间最短路,并预处理:
F[i][sta]表示从家开始,当前走到点i,已经走过sta中的点,走过的最短距离是多少
G[i][sta]表示从花店开始,当前走到点i,已经走过sta中的点,走过的最短距离是多少
枚举先收割哪些花田,记为A,其余的花田记为B
分交货前和交货后两段,单独计算最短距离。以交货前为例:
枚举A中最后一个收割的点i、B中第一个收割的点j
求min{F[i][A]+dis(i,j)+G[j][B]}

T1

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;int n,ans;int query(int x,int y){    int dx,dy,s=0;    dx=log2(x),dy=log2(y);    x/=(1<<(dx-dy));    s+=dx-dy;    dx=dy;    while(x!=y)    {        x/=2,y/=2;        s+=2;    }    return s;}int main(){    freopen("city.in","r",stdin);    freopen("city.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        if(x<y) swap(x,y);        ans=query(x,y);        printf("%d\n",ans);    }    return 0;}

T3

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define LL long longusing namespace std;const int N=27;const int M=(1<<20);int n,m,S,dis[N][N];int f[N][M],g[N][M],ans,num[M];int main(){    freopen("vanilla.in","r",stdin);    freopen("vanilla.out","w",stdout);    memset(dis,127/3,sizeof(dis));    memset(f,127/3,sizeof(f));    memset(g,127/3,sizeof(g));    scanf("%d%d",&n,&m);    S=(1<<n-2)-1;    for(int s=0;s<S;s++)      for(int x=s;x;x>>=1) num[s]+=x&1;    for(int i=1;i<=m;i++)    {        int x,y,z;        scanf("%d%d%d",&x,&y,&z);        dis[x][y]=dis[y][x]=z;    }    for(int i=0;i<n;i++) dis[i][i]=0;    for(int i=0;i<n;i++)     for(int j=0;j<n;j++)      for(int k=0;k<n;k++)       dis[j][k]=min(dis[j][k],dis[j][i]+dis[i][k]);    if(n==3)    {        printf("%d",(dis[0][1]+dis[1][2])*2);        return 0;    }    for(int i=0;i<n-2;i++) f[i][(1<<i)]=dis[0][i+1],g[i][(1<<i)]=dis[n-1][i+1];    for(int i=0;i<n-2;i++) f[i][0]=0,g[i][0]=0;    for(int s=0;s<=S;s++)    {        for(int i=0;i<n-2;i++)         if((1<<i)&s)         {            for(int j=0;j<n-2;j++)             if(!((1<<j)&s))             {                 f[j][s|(1<<j)]=min(f[i][s]+dis[i+1][j+1],f[j][s|(1<<j)]);                 g[j][s|(1<<j)]=min(g[i][s]+dis[i+1][j+1],g[j][s|(1<<j)]);             }         }       }    ans=1e9;    for(int s=0;s<=S;s++)    {        int sum=1e9;        if(num[s]!=(n-2)/2) continue;        for(int i=0;i<n-2;i++)         if((1<<i)&s)          for(int j=0;j<n-2;j++)           if((1<<j)&(S^s)){               sum=min(sum,f[i][s]+dis[i+1][j+1]+g[j][s^S]);           }            for(int i=0;i<n-2;i++)         if((1<<i)&s)          for(int j=0;j<n-2;j++)//集合虽然已经固定,但是两个集合内部的顺序是可以调的           if((1<<j)&(S^s)){               ans=min(ans,sum+g[i][s]+dis[i+1][j+1]+f[j][s^S]);           }    }    printf("%d\n",ans);    return 0;}
原创粉丝点击