JZOJ 3.2 A组总结

T1

Description

  贝希被困在一个三角形的迷宫之中。这个迷宫有N行(1 <= N <= 1000000)。比如下图是一个3行的迷宫。
  
  迷宫的第i行有2*i-1个三角形,从左到右分别编号为(i,1)、(i,2)等等。贝希每次可以从一个三角形走到任意一个一个跟当前的三角形有邻边的三角形。比如说,如果她目前处于三角形(3,3),那么,她可以走到三角形(3,2)、(3,4)和(4,4)。贝希每次需要一分钟的时间来移动到下一个三角形。
  
  农夫约翰发现贝希被困了!于是她跟踪贝希的iPhone手机(可怜的触摸屏~),得知贝希目前处于三角形(Si,Sj)。因为约翰对贝希有着无穷无尽的浓浓爱意,所以他希望贝希能尽可能快地回到他的身边。
  在迷宫的三角形之中,有M(1 <= M <= 10000)个是出口。在任何一个出口都可以让贝希逃离迷宫。一旦贝希进入一个作为出口的三角形,她用多一分钟就可以逃离这个迷宫。
  找到一个可以让贝希逃离迷宫最小时间T,并输出她应该从哪一个出口逃离迷宫,这个出口记为(OUTi,OUTj)。如果有多个出口同时需要时间T,输出那个行的编号小的出口,如果仍然有多个出口,输出那个列的编号小的。
 

Input

  第一行:两个由空格隔开的整数:N和M。
  第二行:两个由空格隔开的整数:Si和Sj。
  第三到第M+2行:第i+2行有两个由空格隔开的整数Ei和Ej,表示三角形(Ei,Ej)是出口。

Output

  第一行:两个由空格隔开的整数:OUTi和OUTj。
  第二行:一个单独的整数:T。
 

Sample Input

4 2
2 1
3 5
4 4

Sample Output

4 4
4
 

Data Constraint

分析

水题,设每个小三角形的坐标为(x,y,z),x表示三角形正着放的时候的层数,y表示三角形旋转60°的层数,z则是旋转120°的

然后到每个出口的时间就是|sx-xi|+|sy-yi|+|sz-zi|

坐标怎么计算很简单

 

#include <iostream>
#include <cstdio>
using namespace std;
const int N=1e6+10;
int n,m,sx,sy,out[2];

int abs(int x) {
    return x<0?-x:x;
}

int main() {
    scanf("%d%d%d%d",&n,&m,&sx,&sy);
    int ans=2147483647;
    for (int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        int k=abs(sx-x)+abs((sx*2-sy+1>>1)-(x*2-y+1>>1))+abs((sy-1>>1)-(y-1>>1));
        if (ans>=k) {
            if (ans==k) {
                if (out[0]>=x) {
                    out[0]=x;
                    if (out[0]==x&&out[1]>y) out[1]=y;
                }
            }
            else
            out[0]=x,out[1]=y;
            ans=k;
        }
    }
    printf("%d %d\n%d\n",out[0],out[1],ans+1);
}
View Code

T2

Description

  邮局需要你来帮助他们为某个邮递员设计出一条能够穿过那遥远乡村的所有村子和小路至少一次的邮路(输入数据将会保证这么一条路是一定存在的)。
  但是,每条路线都是有一个花费的。各个村子里的村民希望邮递员到达他们村子的时间越早越好。因此,各个村子里的人们采用了一些措施:假设第i号村子是邮递员在他的邮递路线上到达的第k个不同的村子。如果k<=w( i ),那么这个村子的村民就会付给邮局w( i )-k欧元。当然,如果k>w(i),邮局也同意付k- w( i )欧元给这个村子,重复经过村子不重复收费。此外,邮递员每经过一条小路,邮局也要付给邮递员1欧元作为补贴。
  现在有n个村子,编号依次为1到n。邮局就位于1号村子,因此邮递员的传递路线从这里开始,也从这个村子结束。能够离开每个村子的路口的数目一定是2,4或者8。这里允许出现同样的村子间存在多条小路,或者某条小路构成了一个自环的情况。
  你的任务是设计一个路线使得邮局赚的钱最多(或者说赔的钱最少。如果有多种最优解,输出字典序最小的。
 

Input

  第一行:两个整数n,m,分别表示村子的数量和小路的数量。
  接下来n行,每行一个整数:w(i)(1≤w(i)<1 000)
  接下来m行,每行两个整数u,v,表示这条小路连接的村子的编号。

Output

  第一行:一个整数k,你的程序所设计的路径的长度
  第二行:k+1个整数,v1,v2…vk+l,每个数之间用一个空格隔开,表示你设计的路径所经过的村子的编号,其中需要满足v1=vk+1=1
 

Sample Input

6 7
1
7
4
10
20
5
2 4
1 5
2 1
4 5
3 6
1 6
1 3

Sample Output

7
1 2 4 5 1 3 6 1
 

Data Constraint

 
 

Hint

【样例说明】


【数据说明】
  对于30%的数据,有N<=20
  对于100%的数据,有N<=200;

分析

乍一看像个树形DP,事实上不是。

ans=1-w[]+2-w[]+..+3-w[]+路径长度

然后思考一下其实走到的顺序与最终值无关,最终值大小只跟路径长度有关

然后说明度只能是偶数,那就随便搞个欧拉回路就好了

 

#include <iostream>
#include <cstdio>
using namespace std;
const int N=210;
int g[N][N],ans[100010];
int n,m;

void DFS(int u) {
    for (int i=1;i<=n;i++)
        if (g[u][i])
            g[u][i]--,g[i][u]--,DFS(i);
    ans[++ans[0]]=u;
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i=1,w;i<=n;i++) scanf("%d",&w);
    for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),g[u][v]++,g[v][u]++;
    DFS(1);
    printf("%d\n",ans[0]-1);
    for (int i=ans[0];i;i--) printf("%d ",ans[i]);
}
View Code

T3

Description

这次的任务很简单,给出了一张有N个点M条边的加权有向无环图,接下来有Q个询问,每个询问包括2个节点X和Y,要求算出从X到Y的一条路径,使得密度最小(密度的定义为,路径上边的权值和除以边的数量)。
 

Input

第一行包括2个整数N和M。
以下M行,每行三个数字A、B、W,表示从A到B有一条权值为W的有向边。
再下一行有一个整数Q。
以下Q行,每行一个询问X和Y,如题意所诉。

Output

对于每个询问输出一行,表示该询问的最小密度路径的密度(保留3位小数),如果不存在这么一条路径输出“OMG!”(不含引号)。
 

Sample Input

3 3
1 3 5
2 1 6
2 3 6
2
1 3
2 3

Sample Output

5.000
5.500
 

Data Constraint

 
 

Hint

【数据规模】
对于60%的数据,有1 ≤ N ≤ 10,1 ≤ M ≤ 100,1 ≤ W ≤ 1000,1 ≤ Q ≤ 1000;
对于100%的数据,有1 ≤ N ≤ 50,1 ≤ M ≤ 1000,1 ≤ W ≤ 100000,1 ≤ Q ≤ 100000。

分析

Floyd即可。。多加一维统计经过路径条数。。卡常就过了

 

#include <cstdio>
using namespace std;
const int N=60;
const int M=1e3+10;
int n,m,q;
int g[N][N][M];

inline int min(int a,int b)  {
    return a>b?b:a;
}

inline double dmin(double a,double b)  {
    return a>b?b:a;
}

int main() {
    scanf("%d%d",&n,&m);
    for (register int i=1;i<=n;i++)
        for (register int j=1;j<=n;j++)
            for (register int k=1;k<=m;k++) g[i][j][k]=0x3f3f3f3f;
    for (register int i=1,u,v,w;i<=m;++i) scanf("%d%d%d",&u,&v,&w),g[u][v][1]=min(g[u][v][1],w);
    for (register int k=2;k<=m;++k)
        for (register int l=1;l<=n;++l)
            for (register int i=1;i<=n;++i)
                for (register int j=1;j<=n;++j) g[i][j][k]=min(g[i][j][k],g[i][l][k-1]+g[l][j][1]);
    for (scanf("%d",&q);q;--q) {
        int a,b;
        double ans=2147483647.0;
        scanf("%d%d",&a,&b);
        for (register int i=1;i<=n;++i) if (g[a][b][i]!=0x3f3f3f3f) ans=dmin(ans,(double)g[a][b][i]/i);
        if (ans==2147483647.0) printf("OMG!\n");
        else printf("%.3lf\n",ans);
    }
}
View Code

 

posted @ 2019-03-04 20:47  Vagari  阅读(246)  评论(0编辑  收藏  举报