1 条题解
-
0
题目描述
有
N
头奶牛(3
<=N
<=100
)在田地中间吃草。为了防止它们走丢,农夫约翰想把它们连成一个圈,即奶牛i
与奶牛i-1
和i+1
相连(奶牛N
与奶牛1
相连以完成这个圈)。每头奶牛都有一些它喜欢的吃草地点,并且只有当它位于其中一个喜欢的地点时才会开心。假设农夫约翰在安置奶牛时必须保证它们开心,计算他将所有奶牛连成圈所需的最短绳子长度。圈的不同部分可能会相互交叉。
输入
- 第一行:整数
N
。 - 第
2
行到第N+1
行:每行描述一头奶牛,使用几个空格分隔的整数。第一个整数是这头奶牛喜欢的地点数量S
(1
<=S
<=40
)。接下来是2*S
个整数,表示这些地点的(x, y)
坐标。坐标范围是-100
到100
。
输出
一行,包含一个整数,表示所需的最短绳子长度的
100
倍(对于这个结果不需要进行特殊的四舍五入)。示例输入
4 1 0 0 2 1 0 2 0 3 -1 -1 1 1 2 2 2 0 1 0 2
示例输出
400
提示
[奶牛
1
位于(0,0)
;奶牛2
位于(1,0)
;奶牛3
位于(1,1)
;奶牛4
位于(0,1)
。]来源
USACO 2003 年 2 月 Orange 组
题意分析
已知有
N
头奶牛在田地中吃草,为防止奶牛走丢,农夫约翰要将奶牛连成一个圈(奶牛i
和奶牛i - 1
、奶牛i + 1
相连,奶牛N
和奶牛1
相连)。每头奶牛都有若干个喜欢的吃草地点,且只有在喜欢的地点时奶牛才会开心。现在需要在保证每头奶牛都开心(即每头奶牛都在自己喜欢的地点)的前提下,计算将所有奶牛用绳子连成圈所需的最短绳子长度,最后输出最短绳子长度的100
倍。解题思路
- 数据输入与初始化:读入奶牛的数量
n
以及每头奶牛喜欢的地点数量s[i]
和地点坐标,并将每个奶牛喜欢的地点信息存储在v[i]
中。同时,初始化距离数组dis[j][k]
,表示第j
头奶牛的第k
个喜欢的地点与其他奶牛喜欢的地点之间的距离,初始值设为一个很大的数999999999
。 - 计算距离:
- 首先,对于奶牛
1
的每个喜欢的地点i
,计算它与奶牛2
的每个喜欢的地点j
之间的距离,并存储在dis[2][j]
中。 - 然后,对于奶牛
3
到奶牛n
,对于每头奶牛j
的每个喜欢的地点k
,遍历前一头奶牛j - 1
的所有喜欢的地点l
,计算从奶牛j - 1
的地点l
到奶牛j
的地点k
的距离td
,更新dis[j][k]
为dis[j][k]
和td + dis[j - 1][l]
中的较小值。 - 最后,对于奶牛
n
的每个喜欢的地点j
,计算从奶牛1
的地点i
到奶牛n
的地点j
的距离td
,更新dis[1][i]
为dis[1][i]
和td + dis[n][j]
中的较小值。
- 首先,对于奶牛
- 确定最短距离:在对奶牛
1
的所有喜欢的地点进行上述操作后,ans
初始值为-1
,通过比较ans
和dis[1][i]
,取较小值更新ans
,最终得到最短的绳子长度。 - 输出结果:将
ans
乘以100
,转换为题目要求的输出格式(最短绳子长度的100
倍),并输出结果。
算法标签
- 图论 - 路径规划:将奶牛及其喜欢的地点看作图中的节点,奶牛之间的连接关系看作边,通过计算节点之间的距离来规划最短路径(绳子长度)。
- 动态规划:在计算每头奶牛的每个喜欢的地点与其他奶牛喜欢的地点之间的距离时,利用动态规划的思想,通过状态转移方程
dis[j][k]=dis[j][k]>td+dis[j-1][l]?td+dis[j-1][l]:dis[j][k]
来更新距离,以找到最短的连接路径。 - 暴力枚举:对奶牛
1
的每个喜欢的地点进行枚举,计算不同情况下的最短绳子长度,最后取最小值,属于暴力枚举的思想。
代码实现
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> using namespace std; struct point { double x; double y; }; vector<point> v[110]; double dist(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double dis[110][50]; int main() { int n,i,j,t,k,l,s[110]; double td,ans; point p; scanf("%d",&n); for (i=1; i<=n; i++) { scanf("%d",s+i); v[i].clear(); for (j=0; j<s[i]; j++) { scanf("%lf%lf",&p.x,&p.y); v[i].push_back(p); } } ans=-1; for (i=0; i<s[1]; i++) { for (j=1; j<=n; j++) { for (k=0; k<s[j]; k++) { dis[j][k]=999999999; } } for (j=0; j<s[2]; j++) { dis[2][j]=dist(v[1][i],v[2][j]); } for (j=3; j<=n; j++) { for (k=0; k<s[j]; k++) { for (l=0; l<s[j-1]; l++) { td=dist(v[j-1][l],v[j][k]); dis[j][k]=dis[j][k]>td+dis[j-1][l]?td+dis[j-1][l]:dis[j][k]; } } } for (j=0; j<s[n]; j++) { td=dist(v[1][i],v[n][j]); dis[1][i]=dis[1][i]>td+dis[n][j]?td+dis[n][j]:dis[1][i]; } if (ans == -1 || ans > dis[1][i]) ans=dis[1][i]; } // for (j=1; j<=n; j++) // { // for (k=0; k<v[j].size(); k++) // { // printf("%f ",dis[j][k]); // dis[j][k]=999999999; // } // printf("\n"); // } ans*=100.0; printf("%d\n",(int)ans); }
- 第一行:整数
- 1
信息
- ID
- 1138
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者