http://poj.org/problem?id=1944
Fiber Communications
TimeLimit: 1000MS MemoryLimit: 30000K
题目大意:
1~n个点依次排列,首尾相接,组成一个环。现在给出p对点,要求这中任意一对点之间要有线相连。
要求:一条线只能连接相邻的两个点。问至少要多少条线才能满足条件。
Sample Input
5 2
1 3
4 5
Sample Output
3
Hint
[Which connectbarn pairs 1-2, 2-3, and 4-5.]
解法:
思路还是看了网上的题解。由于要求的是最少的线数,因此环中至少有一个断点。依次枚举每一个点作为一定存在的断点,然后对每种情况对进行讨论,再计算即可。
细节呈现在代码及注释中。其中to[]数组就是DP数组。
340K 125MS
/*
从头断环为链,之后只讨论从左向右的连接。
由于整个连通环至少有一个断点,因此逐个枚举断点(并非唯一的断点,而是一定存在的断点),
再计算这种情况下的连线数即可。
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=1010;
struct E{int st,ed;}e[inf*10];
int to[inf];//to[i]记录与第i个点连接的最右边的点
int n,p;
int ans=0x7fffffff;
int main(){
cin>>n>>p;
for (int i=1;i<=p;i++){
scanf("%d%d",&e[i].st,&e[i].ed);
if (e[i].st>e[i].ed)
swap(e[i].st,e[i].ed);
}
for (int i=1;i<=n;i++){ //枚举断点的位置
memset(to,0,sizeof(to));
for (int j=1;j<=p;j++){ //对每一对要求相连的点进行讨论
int u=e[j].st, v=e[j].ed;
if (u<i && i<v) { //断点在这对点中间,则连线要从链两头绕过(实质就是环)
to[1]=max(to[1],u);
to[v]=n+1; //这样在计算边数时相当于从n~1有连线
}
else //断点不在这对点中间,则连线从这对点中间经过即可
to[u]=max(to[u],v);
}
int sum=0, //统计的边数
r=0; //目前已连接的最右边的点
for (int j=1;j<=n;j++){ //逐个点统计
if (!to[j]) //这个点没有向右连边
continue;
if (j>r){ //then j连的边之前一定没有连过
sum+=to[j]-j;
r=to[j];
}
else //j连的边之前可能被连过一部分
if (to[j]>r){ //j~r段已经连过,r~to[j]段还没有连
sum+=to[j]-r;
r=to[j];
}
}
ans=min(ans,sum);
}
cout<<ans;
return 0;
}
本文介绍了一道经典算法题FiberCommunications的解决方案,该问题要求在环形布局中找到使得特定点对相连所需的最少连线数量。通过枚举环中的断点并采用动态规划思想来优化计算过程。
1850

被折叠的 条评论
为什么被折叠?



