题意:题目意思看了好久才看懂
有N个戒指,M条长度相同的绳子,然后双手任取两个戒指用力往左右拉,使得中间有些绳子会绷直,问最多能绷直的绳子条数?
分析:把戒指看成点,可知两个点拉长的长度必定是两点之间的最短距离,而拉直的线必定是最短距离上的。但是最短距离上的点之间的连线确不一定能绷直。
如下图:
1,2之间2,3之间能绷直,但是1,3之间不能绷直。 我们可以得出如果点对属于同一级则之间的线不能绷直(同一级指到起始点的距离相等),所以我们先做一遍Floyed,然后枚举左右的两个点,找出这两点最短路上的所有点,在枚举这些点对找能绷直的绳。
c++代码
#include<cstdio>
#include<cstring>
int a[150][150],s[150];
int f[150][150];
int n;
const int INF = 9999999;
void init()
{
int m,i,j,x,y;
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
f[i][j] = INF;
//
for (i = 1; i <= m; i++)
{
scanf("%d%d",&x,&y);
x++,y++;
a[y][x] = a[x][y] = 1;
f[x][y] = f[y][x] = 1;
}
for (i = 1; i <= n; i++)
{
f[i][i] = 0;
a[i][i] = 1;
}
}
void floyed()
{
int k,i,j;
for (k = 1; k <= n; k++)
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
if (f[i][j] > f[i][k] + f[k][j])
f[i][j] = f[i][k] + f[k][j];
}
void work()
{
int i,j,k,k1,k2,tot,ans,ans1;
ans = 0;
for (i = 1; i <= n; i++)
for (j = i+1; j <= n; j++)
if (i != j && f[i][j] != INF)
{
tot = 0;
ans1 = 0;
for (k = 1; k <= n; k++)
if (f[i][k] + f[k][j] == f[i][j]) s[++tot] = k;
for (k1 = 1; k1 <= tot; k1++)
for (k2 = k1 + 1; k2 <= tot; k2++)
{
if (a[s[k1]][s[k2]] == 1 && f[i][s[k1]] != f[i][s[k2]]) ans1++;
}
if (ans < ans1) ans = ans1;
}
printf("%d\n",ans);
}
int main()
{
int temp,kase;
scanf("%d",&temp);
for (kase = 1; kase <= temp; kase++)
{
init();
floyed();
printf("Case #%d: ",kase);
work();
}
return 0;
}