刷题#R14

100 篇文章 0 订阅
57 篇文章 0 订阅

三向城
题目描述
三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口。(来自取名力为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 long
using 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值